taskjuggler 0.0.2
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/COPYING +280 -0
- data/README +31 -0
- data/Rakefile +20 -0
- data/benchmarks/UTF-8-Strings.rb +58 -0
- data/benchmarks/allocate.tjp +30 -0
- data/benchmarks/booking.tjp +62 -0
- data/benchmarks/depends.tjp +112 -0
- data/benchmarks/htmltaskreport.tjp +45 -0
- data/benchmarks/runbench.rb +24 -0
- data/bin/tj3 +3 -0
- data/bin/tj3man +3 -0
- data/doc/classes/AppConfig.html +808 -0
- data/doc/classes/Arguments.html +226 -0
- data/doc/classes/String.html +395 -0
- data/doc/classes/TaskJuggler.html +1358 -0
- data/doc/classes/TaskJuggler/Account.html +257 -0
- data/doc/classes/TaskJuggler/AccountScenario.html +218 -0
- data/doc/classes/TaskJuggler/Allocation.html +419 -0
- data/doc/classes/TaskJuggler/AllocationAttribute.html +291 -0
- data/doc/classes/TaskJuggler/AttributeBase.html +608 -0
- data/doc/classes/TaskJuggler/AttributeDefinition.html +259 -0
- data/doc/classes/TaskJuggler/Booking.html +307 -0
- data/doc/classes/TaskJuggler/BookingListAttribute.html +263 -0
- data/doc/classes/TaskJuggler/BooleanAttribute.html +261 -0
- data/doc/classes/TaskJuggler/CSVFile.html +325 -0
- data/doc/classes/TaskJuggler/Charge.html +279 -0
- data/doc/classes/TaskJuggler/ChargeListAttribute.html +229 -0
- data/doc/classes/TaskJuggler/ChargeSet.html +440 -0
- data/doc/classes/TaskJuggler/ChargeSetListAttribute.html +276 -0
- data/doc/classes/TaskJuggler/ColumnTable.html +260 -0
- data/doc/classes/TaskJuggler/DateAttribute.html +194 -0
- data/doc/classes/TaskJuggler/DependencyListAttribute.html +267 -0
- data/doc/classes/TaskJuggler/DurationAttribute.html +229 -0
- data/doc/classes/TaskJuggler/FixnumAttribute.html +194 -0
- data/doc/classes/TaskJuggler/FlagListAttribute.html +263 -0
- data/doc/classes/TaskJuggler/FloatAttribute.html +229 -0
- data/doc/classes/TaskJuggler/GanttChart.html +667 -0
- data/doc/classes/TaskJuggler/GanttContainer.html +441 -0
- data/doc/classes/TaskJuggler/GanttHeader.html +280 -0
- data/doc/classes/TaskJuggler/GanttHeaderScaleItem.html +245 -0
- data/doc/classes/TaskJuggler/GanttLine.html +398 -0
- data/doc/classes/TaskJuggler/GanttLoadStack.html +327 -0
- data/doc/classes/TaskJuggler/GanttMilestone.html +415 -0
- data/doc/classes/TaskJuggler/GanttRouter.html +425 -0
- data/doc/classes/TaskJuggler/GanttTaskBar.html +429 -0
- data/doc/classes/TaskJuggler/HTMLDocument.html +240 -0
- data/doc/classes/TaskJuggler/HTMLGraphics.html +231 -0
- data/doc/classes/TaskJuggler/Interval.html +552 -0
- data/doc/classes/TaskJuggler/IntervalListAttribute.html +267 -0
- data/doc/classes/TaskJuggler/KeywordDocumentation.html +796 -0
- data/doc/classes/TaskJuggler/Limits.html +416 -0
- data/doc/classes/TaskJuggler/Limits/Limit.html +381 -0
- data/doc/classes/TaskJuggler/LimitsAttribute.html +261 -0
- data/doc/classes/TaskJuggler/Log.html +613 -0
- data/doc/classes/TaskJuggler/LogicalAttribute.html +226 -0
- data/doc/classes/TaskJuggler/LogicalExpression.html +251 -0
- data/doc/classes/TaskJuggler/LogicalFlag.html +229 -0
- data/doc/classes/TaskJuggler/LogicalFunction.html +324 -0
- data/doc/classes/TaskJuggler/LogicalOperation.html +299 -0
- data/doc/classes/TaskJuggler/Macro.html +194 -0
- data/doc/classes/TaskJuggler/MacroParser.html +360 -0
- data/doc/classes/TaskJuggler/MacroTable.html +366 -0
- data/doc/classes/TaskJuggler/Message.html +281 -0
- data/doc/classes/TaskJuggler/MessageHandler.html +215 -0
- data/doc/classes/TaskJuggler/Project.html +1606 -0
- data/doc/classes/TaskJuggler/ProjectFileParser.html +412 -0
- data/doc/classes/TaskJuggler/PropertyList.html +597 -0
- data/doc/classes/TaskJuggler/PropertySet.html +1200 -0
- data/doc/classes/TaskJuggler/PropertyTreeNode.html +1449 -0
- data/doc/classes/TaskJuggler/Query.html +600 -0
- data/doc/classes/TaskJuggler/RealFormat.html +252 -0
- data/doc/classes/TaskJuggler/ReferenceAttribute.html +194 -0
- data/doc/classes/TaskJuggler/Report.html +528 -0
- data/doc/classes/TaskJuggler/ReportElement.html +1070 -0
- data/doc/classes/TaskJuggler/ReportTable.html +497 -0
- data/doc/classes/TaskJuggler/ReportTableCell.html +518 -0
- data/doc/classes/TaskJuggler/ReportTableColumn.html +364 -0
- data/doc/classes/TaskJuggler/ReportTableElement.html +644 -0
- data/doc/classes/TaskJuggler/ReportTableLegend.html +343 -0
- data/doc/classes/TaskJuggler/ReportTableLine.html +431 -0
- data/doc/classes/TaskJuggler/Resource.html +211 -0
- data/doc/classes/TaskJuggler/ResourceListAttribute.html +267 -0
- data/doc/classes/TaskJuggler/ResourceListRE.html +249 -0
- data/doc/classes/TaskJuggler/ResourceScenario.html +1137 -0
- data/doc/classes/TaskJuggler/RichText.html +537 -0
- data/doc/classes/TaskJuggler/RichTextAttribute.html +229 -0
- data/doc/classes/TaskJuggler/RichTextDocument.html +418 -0
- data/doc/classes/TaskJuggler/RichTextElement.html +829 -0
- data/doc/classes/TaskJuggler/RichTextException.html +212 -0
- data/doc/classes/TaskJuggler/RichTextParser.html +317 -0
- data/doc/classes/TaskJuggler/RichTextProtocolExample.html +303 -0
- data/doc/classes/TaskJuggler/RichTextProtocolHandler.html +194 -0
- data/doc/classes/TaskJuggler/RichTextScanner.html +561 -0
- data/doc/classes/TaskJuggler/RichTextSnip.html +364 -0
- data/doc/classes/TaskJuggler/RichTextSyntaxRules.html +883 -0
- data/doc/classes/TaskJuggler/Scenario.html +163 -0
- data/doc/classes/TaskJuggler/ScenarioData.html +354 -0
- data/doc/classes/TaskJuggler/Scoreboard.html +638 -0
- data/doc/classes/TaskJuggler/Shift.html +255 -0
- data/doc/classes/TaskJuggler/ShiftAssignment.html +488 -0
- data/doc/classes/TaskJuggler/ShiftAssignments.html +715 -0
- data/doc/classes/TaskJuggler/ShiftAssignmentsAttribute.html +261 -0
- data/doc/classes/TaskJuggler/ShiftScenario.html +282 -0
- data/doc/classes/TaskJuggler/SourceFileInfo.html +247 -0
- data/doc/classes/TaskJuggler/StringAttribute.html +229 -0
- data/doc/classes/TaskJuggler/SymbolAttribute.html +194 -0
- data/doc/classes/TaskJuggler/SyntaxReference.html +516 -0
- data/doc/classes/TaskJuggler/TOCEntry.html +242 -0
- data/doc/classes/TaskJuggler/TableColumnDefinition.html +273 -0
- data/doc/classes/TaskJuggler/TableOfContents.html +256 -0
- data/doc/classes/TaskJuggler/Task.html +203 -0
- data/doc/classes/TaskJuggler/TaskDependency.html +251 -0
- data/doc/classes/TaskJuggler/TaskListAttribute.html +267 -0
- data/doc/classes/TaskJuggler/TaskListRE.html +250 -0
- data/doc/classes/TaskJuggler/TaskScenario.html +2206 -0
- data/doc/classes/TaskJuggler/TextParser.html +670 -0
- data/doc/classes/TaskJuggler/TextParser/Pattern.html +923 -0
- data/doc/classes/TaskJuggler/TextParser/Rule.html +779 -0
- data/doc/classes/TaskJuggler/TextParser/StackElement.html +267 -0
- data/doc/classes/TaskJuggler/TextParser/TextParserResultArray.html +212 -0
- data/doc/classes/TaskJuggler/TextParser/TokenDoc.html +221 -0
- data/doc/classes/TaskJuggler/TextScanner.html +708 -0
- data/doc/classes/TaskJuggler/TextScanner/BufferStreamHandle.html +355 -0
- data/doc/classes/TaskJuggler/TextScanner/FileStreamHandle.html +341 -0
- data/doc/classes/TaskJuggler/TextScanner/StreamHandle.html +260 -0
- data/doc/classes/TaskJuggler/TjException.html +185 -0
- data/doc/classes/TaskJuggler/TjTime.html +1845 -0
- data/doc/classes/TaskJuggler/TjpExample.html +310 -0
- data/doc/classes/TaskJuggler/TjpExportRE.html +329 -0
- data/doc/classes/TaskJuggler/TjpSyntaxRules.html +8928 -0
- data/doc/classes/TaskJuggler/UserManual.html +606 -0
- data/doc/classes/TaskJuggler/WorkingHours.html +582 -0
- data/doc/classes/TaskJuggler/WorkingHoursAttribute.html +284 -0
- data/doc/classes/TaskJuggler/XMLBlob.html +207 -0
- data/doc/classes/TaskJuggler/XMLComment.html +206 -0
- data/doc/classes/TaskJuggler/XMLDocument.html +293 -0
- data/doc/classes/TaskJuggler/XMLElement.html +341 -0
- data/doc/classes/TaskJuggler/XMLNamedText.html +174 -0
- data/doc/classes/TaskJuggler/XMLText.html +221 -0
- data/doc/files/COPYING.html +448 -0
- data/doc/files/README.html +134 -0
- data/doc/files/lib/AccountScenario_rb.html +116 -0
- data/doc/files/lib/Account_rb.html +118 -0
- data/doc/files/lib/Allocation_rb.html +118 -0
- data/doc/files/lib/AppConfig_rb.html +116 -0
- data/doc/files/lib/AttributeBase_rb.html +106 -0
- data/doc/files/lib/AttributeDefinition_rb.html +106 -0
- data/doc/files/lib/Attributes_rb.html +130 -0
- data/doc/files/lib/Booking_rb.html +106 -0
- data/doc/files/lib/ChargeSet_rb.html +116 -0
- data/doc/files/lib/Charge_rb.html +116 -0
- data/doc/files/lib/HTMLDocument_rb.html +116 -0
- data/doc/files/lib/Interval_rb.html +116 -0
- data/doc/files/lib/KeywordDocumentation_rb.html +122 -0
- data/doc/files/lib/Limits_rb.html +116 -0
- data/doc/files/lib/Log_rb.html +116 -0
- data/doc/files/lib/LogicalExpression_rb.html +122 -0
- data/doc/files/lib/LogicalFlag_rb.html +116 -0
- data/doc/files/lib/LogicalFunction_rb.html +116 -0
- data/doc/files/lib/LogicalOperation_rb.html +116 -0
- data/doc/files/lib/MacroParser_rb.html +118 -0
- data/doc/files/lib/MacroTable_rb.html +122 -0
- data/doc/files/lib/MessageHandler_rb.html +106 -0
- data/doc/files/lib/Message_rb.html +116 -0
- data/doc/files/lib/ProjectFileParser_rb.html +122 -0
- data/doc/files/lib/Project_rb.html +148 -0
- data/doc/files/lib/PropertyList_rb.html +106 -0
- data/doc/files/lib/PropertySet_rb.html +118 -0
- data/doc/files/lib/PropertyTreeNode_rb.html +106 -0
- data/doc/files/lib/Query_rb.html +116 -0
- data/doc/files/lib/RealFormat_rb.html +106 -0
- data/doc/files/lib/ResourceScenario_rb.html +116 -0
- data/doc/files/lib/Resource_rb.html +118 -0
- data/doc/files/lib/RichTextDocument_rb.html +120 -0
- data/doc/files/lib/RichTextElement_rb.html +120 -0
- data/doc/files/lib/RichTextParser_rb.html +120 -0
- data/doc/files/lib/RichTextProtocolExample_rb.html +120 -0
- data/doc/files/lib/RichTextProtocolHandler_rb.html +106 -0
- data/doc/files/lib/RichTextScanner_rb.html +116 -0
- data/doc/files/lib/RichTextSnip_rb.html +118 -0
- data/doc/files/lib/RichTextSyntaxRules_rb.html +106 -0
- data/doc/files/lib/RichText_rb.html +118 -0
- data/doc/files/lib/ScenarioData_rb.html +118 -0
- data/doc/files/lib/Scenario_rb.html +116 -0
- data/doc/files/lib/Scoreboard_rb.html +106 -0
- data/doc/files/lib/ShiftAssignments_rb.html +116 -0
- data/doc/files/lib/ShiftScenario_rb.html +116 -0
- data/doc/files/lib/Shift_rb.html +118 -0
- data/doc/files/lib/SourceFileInfo_rb.html +106 -0
- data/doc/files/lib/SyntaxReference_rb.html +122 -0
- data/doc/files/lib/TOCEntry_rb.html +118 -0
- data/doc/files/lib/TableColumnDefinition_rb.html +106 -0
- data/doc/files/lib/TableOfContents_rb.html +118 -0
- data/doc/files/lib/TaskDependency_rb.html +106 -0
- data/doc/files/lib/TaskJuggler_rb.html +120 -0
- data/doc/files/lib/TaskScenario_rb.html +116 -0
- data/doc/files/lib/Task_rb.html +118 -0
- data/doc/files/lib/TextParser/Pattern_rb.html +116 -0
- data/doc/files/lib/TextParser/Rule_rb.html +106 -0
- data/doc/files/lib/TextParser/StackElement_rb.html +106 -0
- data/doc/files/lib/TextParser/TokenDoc_rb.html +106 -0
- data/doc/files/lib/TextParser_rb.html +124 -0
- data/doc/files/lib/TextScanner_rb.html +128 -0
- data/doc/files/lib/Tj3Config_rb.html +118 -0
- data/doc/files/lib/TjException_rb.html +106 -0
- data/doc/files/lib/TjTime_rb.html +118 -0
- data/doc/files/lib/TjpExample_rb.html +116 -0
- data/doc/files/lib/TjpSyntaxRules_rb.html +106 -0
- data/doc/files/lib/UTF8String_rb.html +132 -0
- data/doc/files/lib/UserManual_rb.html +124 -0
- data/doc/files/lib/WorkingHours_rb.html +116 -0
- data/doc/files/lib/XMLDocument_rb.html +116 -0
- data/doc/files/lib/XMLElement_rb.html +116 -0
- data/doc/files/lib/reports/CSVFile_rb.html +116 -0
- data/doc/files/lib/reports/ColumnTable_rb.html +116 -0
- data/doc/files/lib/reports/GanttChart_rb.html +122 -0
- data/doc/files/lib/reports/GanttContainer_rb.html +116 -0
- data/doc/files/lib/reports/GanttHeaderScaleItem_rb.html +106 -0
- data/doc/files/lib/reports/GanttHeader_rb.html +116 -0
- data/doc/files/lib/reports/GanttLine_rb.html +126 -0
- data/doc/files/lib/reports/GanttLoadStack_rb.html +116 -0
- data/doc/files/lib/reports/GanttMilestone_rb.html +116 -0
- data/doc/files/lib/reports/GanttRouter_rb.html +106 -0
- data/doc/files/lib/reports/GanttTaskBar_rb.html +116 -0
- data/doc/files/lib/reports/HTMLGraphics_rb.html +106 -0
- data/doc/files/lib/reports/ReportElement_rb.html +118 -0
- data/doc/files/lib/reports/ReportTableCell_rb.html +106 -0
- data/doc/files/lib/reports/ReportTableColumn_rb.html +106 -0
- data/doc/files/lib/reports/ReportTableElement_rb.html +122 -0
- data/doc/files/lib/reports/ReportTableLegend_rb.html +106 -0
- data/doc/files/lib/reports/ReportTableLine_rb.html +116 -0
- data/doc/files/lib/reports/ReportTable_rb.html +118 -0
- data/doc/files/lib/reports/Report_rb.html +126 -0
- data/doc/files/lib/reports/ResourceListRE_rb.html +122 -0
- data/doc/files/lib/reports/TaskListRE_rb.html +122 -0
- data/doc/files/lib/reports/TjpExportRE_rb.html +116 -0
- data/doc/files/lib/taskjuggler3_rb.html +276 -0
- data/doc/files/lib/tj3man_rb.html +189 -0
- data/doc/fr_class_index.html +285 -0
- data/doc/fr_file_index.html +223 -0
- data/doc/fr_method_index.html +1953 -0
- data/doc/index.html +21 -0
- data/doc/rdoc-style.css +299 -0
- data/examples/tutorial.tjp +361 -0
- data/gem_spec.rb +30 -0
- data/lib/Account.rb +50 -0
- data/lib/AccountScenario.rb +39 -0
- data/lib/Allocation.rb +102 -0
- data/lib/AppConfig.rb +134 -0
- data/lib/AttributeBase.rb +131 -0
- data/lib/AttributeDefinition.rb +47 -0
- data/lib/Attributes.rb +478 -0
- data/lib/BatchProcessor.rb +209 -0
- data/lib/Booking.rb +59 -0
- data/lib/Charge.rb +71 -0
- data/lib/ChargeSet.rb +126 -0
- data/lib/HTMLDocument.rb +59 -0
- data/lib/Interval.rb +127 -0
- data/lib/KeywordDocumentation.rb +560 -0
- data/lib/Limits.rb +219 -0
- data/lib/Log.rb +160 -0
- data/lib/LogicalExpression.rb +71 -0
- data/lib/LogicalFlag.rb +34 -0
- data/lib/LogicalFunction.rb +102 -0
- data/lib/LogicalOperation.rb +118 -0
- data/lib/MacroParser.rb +77 -0
- data/lib/MacroTable.rb +84 -0
- data/lib/Message.rb +56 -0
- data/lib/MessageHandler.rb +34 -0
- data/lib/Project.rb +662 -0
- data/lib/ProjectFileParser.rb +333 -0
- data/lib/PropertyList.rb +181 -0
- data/lib/PropertySet.rb +304 -0
- data/lib/PropertyTreeNode.rb +461 -0
- data/lib/Query.rb +227 -0
- data/lib/RealFormat.rb +73 -0
- data/lib/Resource.rb +42 -0
- data/lib/ResourceScenario.rb +511 -0
- data/lib/RichText.rb +147 -0
- data/lib/RichTextDocument.rb +139 -0
- data/lib/RichTextElement.rb +391 -0
- data/lib/RichTextParser.rb +66 -0
- data/lib/RichTextProtocolExample.rb +65 -0
- data/lib/RichTextProtocolHandler.rb +35 -0
- data/lib/RichTextScanner.rb +390 -0
- data/lib/RichTextSnip.rb +104 -0
- data/lib/RichTextSyntaxRules.rb +265 -0
- data/lib/Scenario.rb +27 -0
- data/lib/ScenarioData.rb +65 -0
- data/lib/Scoreboard.rb +141 -0
- data/lib/Shift.rb +48 -0
- data/lib/ShiftAssignments.rb +291 -0
- data/lib/ShiftScenario.rb +46 -0
- data/lib/SourceFileInfo.rb +37 -0
- data/lib/SyntaxReference.rb +284 -0
- data/lib/TOCEntry.rb +76 -0
- data/lib/TableColumnDefinition.rb +54 -0
- data/lib/TableOfContents.rb +46 -0
- data/lib/Task.rb +37 -0
- data/lib/TaskDependency.rb +39 -0
- data/lib/TaskJuggler.rb +84 -0
- data/lib/TaskScenario.rb +1622 -0
- data/lib/TextParser.rb +416 -0
- data/lib/TextParser/Pattern.rb +263 -0
- data/lib/TextParser/Rule.rb +171 -0
- data/lib/TextParser/StackElement.rb +45 -0
- data/lib/TextParser/TokenDoc.rb +38 -0
- data/lib/TextScanner.rb +682 -0
- data/lib/Tj3Config.rb +27 -0
- data/lib/TjException.rb +27 -0
- data/lib/TjTime.rb +395 -0
- data/lib/TjpExample.rb +119 -0
- data/lib/TjpSyntaxRules.rb +4022 -0
- data/lib/UTF8String.rb +100 -0
- data/lib/UserManual.rb +282 -0
- data/lib/WorkingHours.rb +323 -0
- data/lib/XMLDocument.rb +54 -0
- data/lib/XMLElement.rb +175 -0
- data/lib/reports/CSVFile.rb +146 -0
- data/lib/reports/ColumnTable.rb +66 -0
- data/lib/reports/GanttChart.rb +308 -0
- data/lib/reports/GanttContainer.rb +107 -0
- data/lib/reports/GanttHeader.rb +141 -0
- data/lib/reports/GanttHeaderScaleItem.rb +42 -0
- data/lib/reports/GanttLine.rb +329 -0
- data/lib/reports/GanttLoadStack.rb +113 -0
- data/lib/reports/GanttMilestone.rb +80 -0
- data/lib/reports/GanttRouter.rb +375 -0
- data/lib/reports/GanttTaskBar.rb +95 -0
- data/lib/reports/HTMLGraphics.rb +65 -0
- data/lib/reports/Report.rb +344 -0
- data/lib/reports/ReportElement.rb +427 -0
- data/lib/reports/ReportTable.rb +144 -0
- data/lib/reports/ReportTableCell.rb +142 -0
- data/lib/reports/ReportTableColumn.rb +82 -0
- data/lib/reports/ReportTableElement.rb +852 -0
- data/lib/reports/ReportTableLegend.rb +167 -0
- data/lib/reports/ReportTableLine.rb +87 -0
- data/lib/reports/ResourceListRE.rb +72 -0
- data/lib/reports/TaskListRE.rb +73 -0
- data/lib/reports/TjpExportRE.rb +394 -0
- data/lib/taskjuggler3.rb +106 -0
- data/lib/tj3man.rb +88 -0
- data/manual/Day_To_Day_Juggling +168 -0
- data/manual/Getting_Started +61 -0
- data/manual/How_To_Contribute +185 -0
- data/manual/Installation +68 -0
- data/manual/Intro +102 -0
- data/manual/Reporting_Bugs +26 -0
- data/manual/Rich_Text_Attributes +90 -0
- data/manual/TaskJuggler_2x_Migration +40 -0
- data/manual/Tutorial +579 -0
- data/manual/fdl +450 -0
- data/prj_cfg.rb +43 -0
- data/setup.rb +1585 -0
- data/tasks/csts.rake +72 -0
- data/tasks/gem.rake +14 -0
- data/tasks/manual.rake +10 -0
- data/tasks/missing.rake +21 -0
- data/tasks/rcov.rake +14 -0
- data/tasks/rdoc.rake +17 -0
- data/tasks/rexml_fix.rb +16 -0
- data/tasks/rexml_fix_19.rb +49 -0
- data/tasks/show.rake +21 -0
- data/tasks/stats.rake +25 -0
- data/tasks/test.rake +11 -0
- data/test/MessageChecker.rb +53 -0
- data/test/TestSuite/CSV-Reports/celltext-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/celltext.tjp +7 -0
- data/test/TestSuite/CSV-Reports/genrefs +6 -0
- data/test/TestSuite/CSV-Reports/project-1.tji +57 -0
- data/test/TestSuite/CSV-Reports/resourcereport-Reference.csv +4 -0
- data/test/TestSuite/CSV-Reports/resourcereport.tjp +10 -0
- data/test/TestSuite/CSV-Reports/resourcereport_with_tasks-Reference.csv +22 -0
- data/test/TestSuite/CSV-Reports/resourcereport_with_tasks.tjp +11 -0
- data/test/TestSuite/CSV-Reports/sortByTree-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/sortByTree.tjp +8 -0
- data/test/TestSuite/CSV-Reports/sortBy_duration.down-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/sortBy_duration.down.tjp +10 -0
- data/test/TestSuite/CSV-Reports/sortBy_effort.up-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/sortBy_effort.up.tjp +10 -0
- data/test/TestSuite/CSV-Reports/sortBy_plan.start.down-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/sortBy_plan.start.down.tjp +10 -0
- data/test/TestSuite/CSV-Reports/taskreport-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/taskreport.tjp +10 -0
- data/test/TestSuite/CSV-Reports/taskreport_with_resources-Reference.csv +24 -0
- data/test/TestSuite/CSV-Reports/taskreport_with_resources.tjp +11 -0
- data/test/TestSuite/Scheduler/Correct/Allocate.tjp +86 -0
- data/test/TestSuite/Scheduler/Correct/AutomaticMilestones.tjp +63 -0
- data/test/TestSuite/Scheduler/Correct/Booking.tjp +161 -0
- data/test/TestSuite/Scheduler/Correct/Depends.tjp +50 -0
- data/test/TestSuite/Scheduler/Correct/Duration.tjp +34 -0
- data/test/TestSuite/Scheduler/Correct/InheritStartEnd.tjp +129 -0
- data/test/TestSuite/Scheduler/Correct/Limits.tjp +81 -0
- data/test/TestSuite/Scheduler/Correct/MultipleMandatories.tjp +43 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-1.tjp +28 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-2.tjp +33 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-3.tjp +33 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-4.tjp +34 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-5.tjp +62 -0
- data/test/TestSuite/Scheduler/Correct/Precedes.tjp +50 -0
- data/test/TestSuite/Scheduler/Correct/Shift.tjp +102 -0
- data/test/TestSuite/Scheduler/Errors/account_no_leaf.tjp +13 -0
- data/test/TestSuite/Scheduler/Errors/booking_conflict.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/booking_no_duty.tjp +9 -0
- data/test/TestSuite/Scheduler/Errors/booking_on_vacation.tjp +9 -0
- data/test/TestSuite/Scheduler/Errors/container_booking.tjp +14 -0
- data/test/TestSuite/Scheduler/Errors/container_duration.tjp +11 -0
- data/test/TestSuite/Scheduler/Errors/effort_no_allocations.tjp +7 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_1.tjp +19 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_10.tjp +36 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_11.tjp +27 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_12.tjp +20 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_13.tjp +27 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_14.tjp +26 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_2.tjp +24 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_3.tjp +18 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_4.tjp +36 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_5.tjp +37 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_6.tjp +35 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_7.tjp +46 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_8.tjp +51 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_9.tjp +20 -0
- data/test/TestSuite/Scheduler/Errors/maxend.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/maxstart.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/milestone_booking.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/milestone_duration.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/milestone_start_end.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/minend.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/minstart.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/multiple_durations.tjp +11 -0
- data/test/TestSuite/Scheduler/Errors/no_tasks.tjp +6 -0
- data/test/TestSuite/Scheduler/Errors/not_scheduled.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_child.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_multi.tjp +13 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_parent.tjp +11 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_self.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_unknown.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/task_overspecified_1.tjp +9 -0
- data/test/TestSuite/Scheduler/Errors/task_overspecified_2.tjp +14 -0
- data/test/TestSuite/Scheduler/Errors/task_overspecified_3.tjp +14 -0
- data/test/TestSuite/Scheduler/Errors/task_underspecified_1.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/task_underspecified_2.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/task_underspecified_3.tjp +9 -0
- data/test/TestSuite/Syntax/Correct/Account.tjp +53 -0
- data/test/TestSuite/Syntax/Correct/Allocate-1.tjp +24 -0
- data/test/TestSuite/Syntax/Correct/Alternative.tjp +13 -0
- data/test/TestSuite/Syntax/Correct/AutoMacros.tjp +14 -0
- data/test/TestSuite/Syntax/Correct/Booking.tjp +26 -0
- data/test/TestSuite/Syntax/Correct/Caption.tjp +33 -0
- data/test/TestSuite/Syntax/Correct/Celltext.tjp +28 -0
- data/test/TestSuite/Syntax/Correct/Comments.tjp +29 -0
- data/test/TestSuite/Syntax/Correct/Complete.tjp +16 -0
- data/test/TestSuite/Syntax/Correct/CompletedWork.tji +20 -0
- data/test/TestSuite/Syntax/Correct/CriticalPath.tjp +31 -0
- data/test/TestSuite/Syntax/Correct/Currencyformat.tjp +12 -0
- data/test/TestSuite/Syntax/Correct/CustomAttributes.tjp +14 -0
- data/test/TestSuite/Syntax/Correct/Depends1.tjp +22 -0
- data/test/TestSuite/Syntax/Correct/Durations.tjp +29 -0
- data/test/TestSuite/Syntax/Correct/Efficiency.tjp +19 -0
- data/test/TestSuite/Syntax/Correct/Export.tjp +40 -0
- data/test/TestSuite/Syntax/Correct/Flags.tjp +32 -0
- data/test/TestSuite/Syntax/Correct/Freeze.tjp +28 -0
- data/test/TestSuite/Syntax/Correct/Gap.tjp +15 -0
- data/test/TestSuite/Syntax/Correct/HtmlTaskReport.tjp +33 -0
- data/test/TestSuite/Syntax/Correct/Limits-1.tjp +71 -0
- data/test/TestSuite/Syntax/Correct/LoadUnits.tjp +31 -0
- data/test/TestSuite/Syntax/Correct/Macro-1.tjp +19 -0
- data/test/TestSuite/Syntax/Correct/Mandatory.tjp +17 -0
- data/test/TestSuite/Syntax/Correct/Milestone.tjp +12 -0
- data/test/TestSuite/Syntax/Correct/MinMax.tjp +17 -0
- data/test/TestSuite/Syntax/Correct/Numberformat.tjp +12 -0
- data/test/TestSuite/Syntax/Correct/Period.tjp +16 -0
- data/test/TestSuite/Syntax/Correct/Persistent.tjp +11 -0
- data/test/TestSuite/Syntax/Correct/Precedes1.tjp +17 -0
- data/test/TestSuite/Syntax/Correct/Priority.tjp +30 -0
- data/test/TestSuite/Syntax/Correct/Project.tjp +21 -0
- data/test/TestSuite/Syntax/Correct/ProjectIDs.tjp +23 -0
- data/test/TestSuite/Syntax/Correct/RawHTML.tjp +29 -0
- data/test/TestSuite/Syntax/Correct/Reports.tjp +54 -0
- data/test/TestSuite/Syntax/Correct/Resource.tjp +20 -0
- data/test/TestSuite/Syntax/Correct/Responsible.tjp +16 -0
- data/test/TestSuite/Syntax/Correct/Scenario.tjp +15 -0
- data/test/TestSuite/Syntax/Correct/Scheduling.tjp +26 -0
- data/test/TestSuite/Syntax/Correct/Select.tjp +27 -0
- data/test/TestSuite/Syntax/Correct/Shift.tjp +55 -0
- data/test/TestSuite/Syntax/Correct/Simple.tjp +25 -0
- data/test/TestSuite/Syntax/Correct/String.tjp +12 -0
- data/test/TestSuite/Syntax/Correct/Supplement.tjp +24 -0
- data/test/TestSuite/Syntax/Correct/TaskRoot.tjp +34 -0
- data/test/TestSuite/Syntax/Correct/TimeFrame.tjp +19 -0
- data/test/TestSuite/Syntax/Correct/Timezone.tjp +8 -0
- data/test/TestSuite/Syntax/Correct/Vacation.tjp +33 -0
- data/test/TestSuite/Syntax/Correct/csvtest +16 -0
- data/test/TestSuite/Syntax/Correct/manual2example.rb +24 -0
- data/test/TestSuite/Syntax/Correct/tutorial.tjp +485 -0
- data/test/TestSuite/Syntax/Errors/bad_include.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/booking_group.tjp +14 -0
- data/test/TestSuite/Syntax/Errors/booking_milestone.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/booking_no_leaf.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/chargeset.tjp +14 -0
- data/test/TestSuite/Syntax/Errors/chargeset_master.tjp +15 -0
- data/test/TestSuite/Syntax/Errors/container_attribute.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/cost_acct_no_top.tjp +24 -0
- data/test/TestSuite/Syntax/Errors/cost_rev_same.tjp +24 -0
- data/test/TestSuite/Syntax/Errors/date_in_range.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/effort_zero.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/empty.tjp +1 -0
- data/test/TestSuite/Syntax/Errors/export_bad_extn.tjp +9 -0
- data/test/TestSuite/Syntax/Errors/extend_id_cap.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/interval_end_in_range.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/interval_start_in_range.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/leaf_resource_id_expected.tjp +12 -0
- data/test/TestSuite/Syntax/Errors/misaligned_date.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/no_csv_suffix.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/no_html_suffix.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/operand_attribute.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/operand_unkn_flag.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/operand_unkn_scen.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/overtime_range.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/purge_no_list.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/purge_unknown_id.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/report_end.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/report_redifinition.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/report_start.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/resource_exists.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/resource_id_expected.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/rev_acct_no_top.tjp +24 -0
- data/test/TestSuite/Syntax/Errors/scenario_exists.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/shift_assignment_overlap.tjp +15 -0
- data/test/TestSuite/Syntax/Errors/shift_exists.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/shift_id_expected.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/sloppy_range.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/sort_direction.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/sort_unknown_scen.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/sorting_crit_exptd1.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/sorting_crit_exptd2.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/sorting_wbs.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/start_before_end1.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/start_before_end2.tjp +6 -0
- data/test/TestSuite/Syntax/Errors/task_complete.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/task_exists.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/task_priority.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/task_without_chargeset.tjp +9 -0
- data/test/TestSuite/Syntax/Errors/time_interval.tjp +12 -0
- data/test/TestSuite/Syntax/Errors/too_many_bangs.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/undecl_flag.tjp +6 -0
- data/test/TestSuite/Syntax/Errors/unknown_projectid.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/unknown_scenario_id.tjp +6 -0
- data/test/TestSuite/Syntax/Errors/unknown_scenario_idx.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/unknown_task.tjp +10 -0
- data/test/all.rb +31 -0
- data/test/test_BatchProcessor.rb +54 -0
- data/test/test_CSV-Reports.rb +101 -0
- data/test/test_Limits.rb +104 -0
- data/test/test_LogicalExpression.rb +110 -0
- data/test/test_MacroTable.rb +51 -0
- data/test/test_Project.rb +57 -0
- data/test/test_PropertySet.rb +71 -0
- data/test/test_Query.rb +83 -0
- data/test/test_RealFormat.rb +83 -0
- data/test/test_RichText.rb +869 -0
- data/test/test_Scheduler.rb +42 -0
- data/test/test_ShiftAssignments.rb +77 -0
- data/test/test_Syntax.rb +41 -0
- data/test/test_TextScanner.rb +95 -0
- data/test/test_TjTime.rb +114 -0
- data/test/test_TjpExample.rb +169 -0
- data/test/test_UTF8String.rb +84 -0
- data/test/test_WorkingHours.rb +56 -0
- metadata +649 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
#
|
|
4
|
+
# = TextParser/Rule.rb -- The TaskJuggler III Project Management Software
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
|
|
7
|
+
#
|
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
|
10
|
+
# published by the Free Software Foundation.
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
class TaskJuggler::TextParser
|
|
14
|
+
|
|
15
|
+
# The TextParserRule holds the basic elment of the syntax description. Each
|
|
16
|
+
# rule has a name and a set of patterns. The parser uses these rules to parse
|
|
17
|
+
# the input files. The first token of a pattern must resolve to a terminal
|
|
18
|
+
# token. The resolution can run transitively over a set of rules. The first
|
|
19
|
+
# tokens of each pattern of a rule must resolve to a terminal symbol and all
|
|
20
|
+
# terminals must be unique in the scope that they appear in. The parser uses
|
|
21
|
+
# this first token to select the next pattern it uses for the syntactical
|
|
22
|
+
# analysis. A rule can be marked as repeatable and/or optional. In this case
|
|
23
|
+
# the syntax element described by the rule may occur 0 or multiple times in
|
|
24
|
+
# the parsed file.
|
|
25
|
+
class Rule
|
|
26
|
+
|
|
27
|
+
attr_reader :name, :patterns, :optional, :repeatable, :keyword, :doc
|
|
28
|
+
attr_accessor :transitions
|
|
29
|
+
|
|
30
|
+
# Create a new syntax rule called +name+.
|
|
31
|
+
def initialize(name)
|
|
32
|
+
@name = name
|
|
33
|
+
@patterns = []
|
|
34
|
+
@repeatable = false
|
|
35
|
+
@optional = false
|
|
36
|
+
@transitions = []
|
|
37
|
+
# In case a rule is optional or any of the patterns is fully optional,
|
|
38
|
+
# this variable is set to true.
|
|
39
|
+
@transitiveOptional = nil
|
|
40
|
+
@keyword = nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Add a new +pattern+ to the Rule. It should be of type
|
|
44
|
+
# TextParser::Pattern.
|
|
45
|
+
def addPattern(pattern)
|
|
46
|
+
@patterns << pattern
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Mark the rule as an optional element of the syntax.
|
|
50
|
+
def setOptional
|
|
51
|
+
@optional = true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Return true if the rule describes optional elements. The evaluation
|
|
55
|
+
# recursively descends into the pattern if necessary and stores the result
|
|
56
|
+
# to be reused for later calls.
|
|
57
|
+
def optional?(rules)
|
|
58
|
+
# If we have a cached result, use this.
|
|
59
|
+
return @transitiveOptional if @transitiveOptional
|
|
60
|
+
|
|
61
|
+
# If the rule is marked optional, then it is optional.
|
|
62
|
+
if @optional
|
|
63
|
+
return @transitiveOptional = true
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# If all patterns describe optional content, then this rule is optional
|
|
67
|
+
# as well.
|
|
68
|
+
@transitiveOptional = true
|
|
69
|
+
@patterns.each do |pat|
|
|
70
|
+
return @transitiveOptional = false unless pat.optional?(rules)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Mark the syntax element described by this Rule as a repeatable element
|
|
75
|
+
# that can occur once or more times in sequence.
|
|
76
|
+
def setRepeatable
|
|
77
|
+
@repeatable = true
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Add a description for the syntax elements of this Rule. +doc+ is a
|
|
81
|
+
# RichText and +keyword+ is a unique name of this Rule. To avoid
|
|
82
|
+
# ambiguouties, an optional scope can be appended, separated by a dot
|
|
83
|
+
# (E.g. name.scope).
|
|
84
|
+
def setDoc(keyword, doc)
|
|
85
|
+
raise 'No pattern defined yet' if @patterns.empty?
|
|
86
|
+
@patterns[-1].setDoc(keyword, doc)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Add a description for a pattern element of the last added pattern.
|
|
90
|
+
def setArg(idx, doc)
|
|
91
|
+
raise 'No pattern defined yet' if @patterns.empty?
|
|
92
|
+
@patterns[-1].setArg(idx, doc)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Specify the index +idx+ of the last token to be used for the syntax
|
|
96
|
+
# documentation. All subsequent tokens will be ignored.
|
|
97
|
+
def setLastSyntaxToken(idx)
|
|
98
|
+
raise 'No pattern defined yet' if @patterns.empty?
|
|
99
|
+
raise 'Token index too large' if idx >= @patterns[-1].tokens.length
|
|
100
|
+
@patterns[-1].setLastSyntaxToken(idx)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Add a reference to another rule for documentation purposes.
|
|
104
|
+
def setSeeAlso(also)
|
|
105
|
+
raise 'No pattern defined yet' if @patterns.empty?
|
|
106
|
+
@patterns[-1].setSeeAlso(also)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Add a reference to a code example. +file+ is the name of the file. +tag+
|
|
110
|
+
# is a tag within the file that specifies a part of this file.
|
|
111
|
+
def setExample(file, tag)
|
|
112
|
+
@patterns[-1].setExample(file, tag)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Return a reference the pattern of this Rule.
|
|
116
|
+
def pattern(idx)
|
|
117
|
+
@patterns[idx]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Return the pattern of this rule that matches the given +token+. If no
|
|
121
|
+
# pattern matches, return nil.
|
|
122
|
+
def matchingPatternIndex(token)
|
|
123
|
+
@transitions.length.times do |i|
|
|
124
|
+
return i if @transitions[i].has_key?(token)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
nil
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def to_syntax(stack, docs, rules, skip)
|
|
131
|
+
str = ''
|
|
132
|
+
str << '[' if @optional || @repeatable
|
|
133
|
+
str << '(' if @patterns.length > 1
|
|
134
|
+
first = true
|
|
135
|
+
pStr = ''
|
|
136
|
+
@patterns.each do |pat|
|
|
137
|
+
if first
|
|
138
|
+
first = false
|
|
139
|
+
else
|
|
140
|
+
pStr << ' | '
|
|
141
|
+
end
|
|
142
|
+
pStr << pat.to_syntax_r(stack, docs, rules, skip)
|
|
143
|
+
end
|
|
144
|
+
return '' if pStr == ''
|
|
145
|
+
str << pStr
|
|
146
|
+
str << '...' if @repeatable
|
|
147
|
+
str << ')' if @patterns.length > 1
|
|
148
|
+
str << ']' if @optional || @repeatable
|
|
149
|
+
str
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def dump
|
|
153
|
+
puts "Rule: #{name} #{@optional ? "[optional]" : ""} " +
|
|
154
|
+
"#{@repeatable ? "[repeatable]" : ""}"
|
|
155
|
+
@patterns.length.times do |i|
|
|
156
|
+
puts " Pattern: \"#{@patterns[i]}\""
|
|
157
|
+
@transitions[i].each do |key, rule|
|
|
158
|
+
if key[0] == ?_
|
|
159
|
+
token = "\"" + key.slice(1, key.length - 1) + "\""
|
|
160
|
+
else
|
|
161
|
+
token = key.slice(1, key.length - 1)
|
|
162
|
+
end
|
|
163
|
+
puts " #{token} -> #{rule.name}"
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
puts
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
#
|
|
4
|
+
# = TextParser/StackElement.rb -- The TaskJuggler III Project Management Software
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
|
|
7
|
+
#
|
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
|
10
|
+
# published by the Free Software Foundation.
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
class TaskJuggler::TextParser
|
|
14
|
+
|
|
15
|
+
# This class models the elements of the stack that the TextParser uses to keep
|
|
16
|
+
# track of its state. It stores the current TextParserRule, the current
|
|
17
|
+
# pattern position and the TextScanner position at the start of processing. It
|
|
18
|
+
# also store the function that must be called to store the collected values.
|
|
19
|
+
class StackElement
|
|
20
|
+
|
|
21
|
+
attr_reader :val, :rule, :function, :sourceFileInfo
|
|
22
|
+
|
|
23
|
+
# Create a new stack element. _rule_ is the TextParserRule that triggered
|
|
24
|
+
# the creation of this element. _function_ is the function that will be
|
|
25
|
+
# called at the end to store the collected data. _sourceFileInfo_ is a
|
|
26
|
+
# SourceFileInfo reference that describes the TextScanner position when the
|
|
27
|
+
# rule was entered.
|
|
28
|
+
def initialize(rule, function, sourceFileInfo)
|
|
29
|
+
# This Array stores the collected values.
|
|
30
|
+
@val = []
|
|
31
|
+
@position = 0
|
|
32
|
+
@rule = rule
|
|
33
|
+
@function = function
|
|
34
|
+
@sourceFileInfo = sourceFileInfo
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Store a collected value and move the position to the next pattern.
|
|
38
|
+
def store(val)
|
|
39
|
+
@val[@position] = val
|
|
40
|
+
@position += 1
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
#
|
|
4
|
+
# = ParserTokenDoc.rb -- The TaskJuggler III Project Management Software
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
|
|
7
|
+
#
|
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
|
10
|
+
# published by the Free Software Foundation.
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
class TaskJuggler::TextParser
|
|
14
|
+
|
|
15
|
+
# Utility class to store a name and a textual description of the meaning of a
|
|
16
|
+
# token used by the parser syntax tree. A specification of the variable type
|
|
17
|
+
# and a reference to a specific pattern are optional.
|
|
18
|
+
class TokenDoc
|
|
19
|
+
|
|
20
|
+
attr_reader :text
|
|
21
|
+
attr_accessor :name, :typeSpec, :pattern
|
|
22
|
+
|
|
23
|
+
# Construct a ParserTokenDoc object. _name_ and _text_ are Strings that
|
|
24
|
+
# hold the name and textual description of the parser token.
|
|
25
|
+
def initialize(name, arg)
|
|
26
|
+
@name = name
|
|
27
|
+
if arg.is_a?(String)
|
|
28
|
+
@text = arg
|
|
29
|
+
else
|
|
30
|
+
@pattern = arg
|
|
31
|
+
end
|
|
32
|
+
@typeSpec = nil
|
|
33
|
+
@pattern = nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
data/lib/TextScanner.rb
ADDED
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
#
|
|
4
|
+
# = TextScanner.rb -- The TaskJuggler III Project Management Software
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
|
|
7
|
+
#
|
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
|
10
|
+
# published by the Free Software Foundation.
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
require 'UTF8String'
|
|
14
|
+
require 'TjTime'
|
|
15
|
+
require 'TjException'
|
|
16
|
+
require 'SourceFileInfo'
|
|
17
|
+
require 'MacroTable'
|
|
18
|
+
require 'MacroParser'
|
|
19
|
+
require 'Log'
|
|
20
|
+
|
|
21
|
+
class TaskJuggler
|
|
22
|
+
|
|
23
|
+
# The TextScanner class can scan text files and chop then into tokens to be
|
|
24
|
+
# used by a parser. Files can be nested. A file can include an other file.
|
|
25
|
+
class TextScanner
|
|
26
|
+
|
|
27
|
+
# This class is used to handle the low-level input operations. It knows
|
|
28
|
+
# whether it deals with a text buffer or a file and abstracts this to the
|
|
29
|
+
# TextScanner. For each nested file the scanner puts an StreamHandle on the
|
|
30
|
+
# stack while the file is scanned. With this stack the scanner can resume
|
|
31
|
+
# the processing of the enclosing file once the included files has been
|
|
32
|
+
# completely processed.
|
|
33
|
+
class StreamHandle
|
|
34
|
+
|
|
35
|
+
attr_accessor :lineNo, :columnNo, :line, :charBuffer
|
|
36
|
+
attr_reader :fileName
|
|
37
|
+
|
|
38
|
+
def initialize
|
|
39
|
+
@lineNo = 1
|
|
40
|
+
@columnNo = 1
|
|
41
|
+
@line = ""
|
|
42
|
+
@charBuffer = []
|
|
43
|
+
@fileName = nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def dirname
|
|
47
|
+
@fileName ? File.dirname(@fileName) : ''
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Specialized version of StreamHandle for operations on files.
|
|
53
|
+
class FileStreamHandle < StreamHandle
|
|
54
|
+
|
|
55
|
+
attr_reader :fileName
|
|
56
|
+
|
|
57
|
+
def initialize(fileName)
|
|
58
|
+
super()
|
|
59
|
+
@fileName = fileName
|
|
60
|
+
@file = File.new(fileName, 'r')
|
|
61
|
+
@bytes = 0
|
|
62
|
+
Log << "Parsing file #{@fileName} ..."
|
|
63
|
+
Log.startProgressMeter("Reading file #{fileName}")
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def close
|
|
68
|
+
@file.close
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def getc19
|
|
72
|
+
Log.activity if @bytes & 0x3FFF == 0
|
|
73
|
+
@bytes += 1
|
|
74
|
+
@file.getc
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def getc18
|
|
78
|
+
Log.activity if @bytes & 0x3FFF == 0
|
|
79
|
+
@bytes += 1
|
|
80
|
+
c = @file.getc
|
|
81
|
+
return nil if c.nil?
|
|
82
|
+
'' << c
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if RUBY_VERSION < '1.9.0'
|
|
86
|
+
alias getc getc18
|
|
87
|
+
else
|
|
88
|
+
alias getc getc19
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Specialized version of StreamHandle for operations on Strings.
|
|
94
|
+
class BufferStreamHandle < StreamHandle
|
|
95
|
+
|
|
96
|
+
def initialize(buffer)
|
|
97
|
+
super()
|
|
98
|
+
@buffer = buffer
|
|
99
|
+
@length = @buffer.length_utf8
|
|
100
|
+
@pos = 0
|
|
101
|
+
Log << "Parsing buffer #{@buffer[0, 20]} ..."
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def close
|
|
105
|
+
@buffer = nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def getc18
|
|
109
|
+
return nil if @pos >= @length
|
|
110
|
+
|
|
111
|
+
c = @buffer[@pos]
|
|
112
|
+
@pos += 1
|
|
113
|
+
'' << c
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def getc19
|
|
117
|
+
return nil if @pos >= @length
|
|
118
|
+
|
|
119
|
+
c = @buffer[@pos]
|
|
120
|
+
@pos += 1
|
|
121
|
+
c
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
if RUBY_VERSION < '1.9.0'
|
|
125
|
+
alias getc getc18
|
|
126
|
+
else
|
|
127
|
+
alias getc getc19
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def fileName
|
|
131
|
+
''
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Create a new instance of TextScanner. _masterFile_ must be a String that
|
|
136
|
+
# either contains the name of the file to start with or the text itself.
|
|
137
|
+
# _messageHandler_ is a MessageHandler that is used for error messages.
|
|
138
|
+
def initialize(masterFile, messageHandler)
|
|
139
|
+
@masterFile = masterFile
|
|
140
|
+
@messageHandler = messageHandler
|
|
141
|
+
# This table contains all macros that may be expanded when found in the
|
|
142
|
+
# text.
|
|
143
|
+
@macroTable = MacroTable.new(messageHandler)
|
|
144
|
+
# This Array stores the currently processed nested files. It's an Array
|
|
145
|
+
# of Arrays. The nested Array consists of 3 elements, the @cf,
|
|
146
|
+
# @tokenBuffer and the @pos of the file.
|
|
147
|
+
@fileStack = []
|
|
148
|
+
# This Array stores the currently processed nested macros.
|
|
149
|
+
@macroStack = []
|
|
150
|
+
# In certain situation we want to ignore Macro replacement and this flag
|
|
151
|
+
# is set to true.
|
|
152
|
+
@ignoreMacros = false
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Start the processing. if _fileNameIsBuffer_ is true, we operate on a
|
|
156
|
+
# String, else on a File.
|
|
157
|
+
def open(fileNameIsBuffer = false)
|
|
158
|
+
if fileNameIsBuffer
|
|
159
|
+
@fileStack = [ [ @cf = BufferStreamHandle.new(@masterFile), nil, nil ] ]
|
|
160
|
+
else
|
|
161
|
+
begin
|
|
162
|
+
@fileStack = [ [ @cf = FileStreamHandle.new(@masterFile), nil, nil ] ]
|
|
163
|
+
rescue StandardError
|
|
164
|
+
raise TjException.new, "Cannot open file #{@masterFile}"
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
@masterPath = @cf.dirname + '/'
|
|
168
|
+
@tokenBuffer = @pos = nil
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Finish processing and reset all data structures.
|
|
172
|
+
def close
|
|
173
|
+
Log.startProgressMeter("Reading file #{@masterFile}")
|
|
174
|
+
Log.stopProgressMeter
|
|
175
|
+
@fileStack = []
|
|
176
|
+
@cf = @tokenBuffer = @pos = nil
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Continue processing with a new file specified by _fileName_. When this
|
|
180
|
+
# file is finished, we will continue in the old file after the location
|
|
181
|
+
# where we started with the new file.
|
|
182
|
+
def include(fileName)
|
|
183
|
+
begin
|
|
184
|
+
if @fileStack.empty?
|
|
185
|
+
path = @masterPath
|
|
186
|
+
else
|
|
187
|
+
path = @fileStack.last[0].dirname + '/'
|
|
188
|
+
@fileStack.last[1, 2] = [ @tokenBuffer, @pos ]
|
|
189
|
+
end
|
|
190
|
+
if fileName[0] != '/'
|
|
191
|
+
# If the included file is not an absolute name, we interpret the file
|
|
192
|
+
# name relative to the including file.
|
|
193
|
+
fileName = path + fileName
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
@tokenBuffer = @pos = nil
|
|
197
|
+
@fileStack << [ (@cf = FileStreamHandle.new(fileName)), nil, nil ]
|
|
198
|
+
rescue StandardError
|
|
199
|
+
error('bad_include', "Cannot open include file #{fileName}")
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Return SourceFileInfo for the current processing prosition.
|
|
204
|
+
def sourceFileInfo
|
|
205
|
+
@pos ? @pos.clone : SourceFileInfo.new(fileName, lineNo, columnNo)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Return the name of the currently processed file. If we are working on a
|
|
209
|
+
# text buffer, the text will be returned.
|
|
210
|
+
def fileName
|
|
211
|
+
@cf ? @cf.fileName : @masterFile
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def lineNo # :nodoc:
|
|
215
|
+
@cf ? @cf.lineNo : 0
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def columnNo # :nodoc:
|
|
219
|
+
@cf ? @cf.columnNo : 0
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def line # :nodoc:
|
|
223
|
+
@cf ? @cf.line : 0
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Scan for the next token in the input stream and return it. The result will
|
|
227
|
+
# be an Array of the form [ TokenType, TokenValue ].
|
|
228
|
+
def nextToken
|
|
229
|
+
# If we have a pushed-back token, return that first.
|
|
230
|
+
unless @tokenBuffer.nil?
|
|
231
|
+
res = @tokenBuffer
|
|
232
|
+
@tokenBuffer = @pos = nil
|
|
233
|
+
return res
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Start processing characters from the input.
|
|
237
|
+
token = [ '.', '<END>' ]
|
|
238
|
+
while c = nextChar
|
|
239
|
+
case c
|
|
240
|
+
when ' ', "\n", "\t"
|
|
241
|
+
if (tok = readBlanks(c))
|
|
242
|
+
token = tok
|
|
243
|
+
break
|
|
244
|
+
end
|
|
245
|
+
when '#'
|
|
246
|
+
skipComment
|
|
247
|
+
when '/'
|
|
248
|
+
skipCPlusPlusComments
|
|
249
|
+
when '0'..'9'
|
|
250
|
+
token = readNumber(c)
|
|
251
|
+
break
|
|
252
|
+
when "'"
|
|
253
|
+
token = readString(c)
|
|
254
|
+
break
|
|
255
|
+
when '"'
|
|
256
|
+
token = readString(c)
|
|
257
|
+
break
|
|
258
|
+
when '!'
|
|
259
|
+
token = readRelativeId(c)
|
|
260
|
+
break
|
|
261
|
+
when 'a'..'z', 'A'..'Z', '_'
|
|
262
|
+
token = readId(c)
|
|
263
|
+
break
|
|
264
|
+
when '['
|
|
265
|
+
token = readMacro
|
|
266
|
+
break
|
|
267
|
+
when nil
|
|
268
|
+
# We've reached an end of file or buffer
|
|
269
|
+
break
|
|
270
|
+
else
|
|
271
|
+
str = ""
|
|
272
|
+
str << c
|
|
273
|
+
token = [ 'LITERAL', str ]
|
|
274
|
+
break
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
@lastPos = @pos
|
|
278
|
+
@pos = SourceFileInfo.new(fileName, lineNo, columnNo)
|
|
279
|
+
return token
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Return a token to retrieve it with the next nextToken() call again. Only 1
|
|
283
|
+
# token can be returned before the next nextToken() call.
|
|
284
|
+
def returnToken(token)
|
|
285
|
+
unless @tokenBuffer.nil?
|
|
286
|
+
$stderr.puts @tokenBuffer
|
|
287
|
+
raise "Fatal Error: Cannot return more than 1 token in a row"
|
|
288
|
+
end
|
|
289
|
+
@tokenBuffer = token
|
|
290
|
+
@pos = @lastPos
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Add a Macro to the macro translation table.
|
|
294
|
+
def addMacro(macro)
|
|
295
|
+
@macroTable.add(macro)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Return true if the Macro _name_ has been added already.
|
|
299
|
+
def macroDefined?(name)
|
|
300
|
+
@macroTable.include?(name)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def expandMacro(args)
|
|
304
|
+
macro, text = @macroTable.resolve(args, sourceFileInfo)
|
|
305
|
+
return if text == ''
|
|
306
|
+
|
|
307
|
+
@macroStack << [ macro, args ]
|
|
308
|
+
# Mark end of macro with a 0 element
|
|
309
|
+
@cf.charBuffer << 0
|
|
310
|
+
text.reverse.each_utf8_char do |c|
|
|
311
|
+
@cf.charBuffer << c
|
|
312
|
+
end
|
|
313
|
+
@cf.line = ''
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# Call this function to report any errors related to the parsed input.
|
|
317
|
+
def error(id, text, property = nil)
|
|
318
|
+
message = Message.new(id, 'error', text + "\n" + line.to_s,
|
|
319
|
+
property, nil, sourceFileInfo)
|
|
320
|
+
@messageHandler.send(message)
|
|
321
|
+
|
|
322
|
+
until @macroStack.empty?
|
|
323
|
+
macro, args = @macroStack.pop
|
|
324
|
+
args.collect! { |a| '"' + a + '"' }
|
|
325
|
+
message = Message.new('macro_stack', 'info',
|
|
326
|
+
" #{macro.name} #{args.join(' ')}", nil, nil,
|
|
327
|
+
macro.sourceFileInfo)
|
|
328
|
+
@messageHandler.send(message)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
raise TjException.new, 'Syntax error during parse'
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
private
|
|
335
|
+
|
|
336
|
+
# This function is called by the scanner to get the next character. It
|
|
337
|
+
# features a FIFO buffer that can hold any amount of returned characters.
|
|
338
|
+
# When it has reached the end of the master file it returns nil.
|
|
339
|
+
def nextChar
|
|
340
|
+
if (c = nextCharI) == '$' && !@ignoreMacros
|
|
341
|
+
# Double $ are reduced to a single $.
|
|
342
|
+
return c if (c = nextCharI) == '$'
|
|
343
|
+
|
|
344
|
+
# Macros start with $( or ${. All other $. are ignored.
|
|
345
|
+
if c != '(' && c != '{'
|
|
346
|
+
returnChar(c)
|
|
347
|
+
return '$'
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
@ignoreMacros = true
|
|
351
|
+
returnChar(c)
|
|
352
|
+
macroParser = MacroParser.new(self, @messageHandler)
|
|
353
|
+
begin
|
|
354
|
+
macroParser.parse('macroCall', false)
|
|
355
|
+
rescue TjException
|
|
356
|
+
end
|
|
357
|
+
@ignoreMacros = false
|
|
358
|
+
return nextCharI
|
|
359
|
+
else
|
|
360
|
+
return c
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def nextCharI
|
|
365
|
+
# This can only happen when a previous call already returned nil.
|
|
366
|
+
return nil if @cf.nil?
|
|
367
|
+
|
|
368
|
+
c = nil
|
|
369
|
+
# If there are characters in the return buffer process them first.
|
|
370
|
+
# Otherwise get next character from input stream.
|
|
371
|
+
unless @cf.charBuffer.empty?
|
|
372
|
+
c = @cf.charBuffer.pop
|
|
373
|
+
@cf.lineNo -= 1 if c == "\n" && !@macroStack.empty?
|
|
374
|
+
while !@cf.charBuffer.empty? && @cf.charBuffer[-1] == 0
|
|
375
|
+
@cf.charBuffer.pop
|
|
376
|
+
@macroStack.pop
|
|
377
|
+
end
|
|
378
|
+
else
|
|
379
|
+
# If EOF has been reached, try the parent file until even the master
|
|
380
|
+
# file has been processed completely.
|
|
381
|
+
if (c = @cf.getc).nil?
|
|
382
|
+
@cf.close
|
|
383
|
+
@fileStack.pop
|
|
384
|
+
if @fileStack.empty?
|
|
385
|
+
# We are done with the top-level file now.
|
|
386
|
+
@cf = @tokenBuffer = @pos = nil
|
|
387
|
+
else
|
|
388
|
+
@cf, @tokenBuffer, @pos = @fileStack.last
|
|
389
|
+
Log << "Parsing file #{@cf.fileName} ..."
|
|
390
|
+
# We have been called by nextToken() already, so we can't just
|
|
391
|
+
# restore @tokenBuffer and be done. We need to feed the token text
|
|
392
|
+
# back into the charBuffer and return the first character.
|
|
393
|
+
if @tokenBuffer
|
|
394
|
+
@tokenBuffer[1].reverse.each_utf8_char do |ch|
|
|
395
|
+
@cf.charBuffer.push(ch)
|
|
396
|
+
end
|
|
397
|
+
@tokenBuffer = nil
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
return nil
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
unless c.nil?
|
|
404
|
+
@cf.lineNo += 1 if c == "\n"
|
|
405
|
+
@cf.line = "" if @cf.line[-1] == ?\n
|
|
406
|
+
@cf.line << c
|
|
407
|
+
end
|
|
408
|
+
c
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def returnChar(c)
|
|
412
|
+
return if @cf.nil?
|
|
413
|
+
|
|
414
|
+
@cf.line.chop! if c
|
|
415
|
+
@cf.charBuffer << c
|
|
416
|
+
@cf.lineNo -= 1 if c == "\n" && @macroStack.empty?
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def skipComment
|
|
420
|
+
# Read all characters until line or file end is found
|
|
421
|
+
@ignoreMacros = true
|
|
422
|
+
while (c = nextChar) && c != "\n"
|
|
423
|
+
end
|
|
424
|
+
@ignoreMacros = false
|
|
425
|
+
returnChar(c)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
def skipCPlusPlusComments
|
|
429
|
+
if (c = nextChar) == '*'
|
|
430
|
+
# /* */ style multi-line comment
|
|
431
|
+
@ignoreMacros = true
|
|
432
|
+
begin
|
|
433
|
+
while (c = nextChar) != '*'
|
|
434
|
+
end
|
|
435
|
+
end until (c = nextChar) == '/'
|
|
436
|
+
@ignoreMacros = false
|
|
437
|
+
elsif c == '/'
|
|
438
|
+
# // style single line comment
|
|
439
|
+
skipComment
|
|
440
|
+
else
|
|
441
|
+
error('bad_comment', "'/' or '*' expected after start of comment")
|
|
442
|
+
end
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def readBlanks(c)
|
|
446
|
+
loop do
|
|
447
|
+
if c == ' '
|
|
448
|
+
if (c2 = nextChar) == '-'
|
|
449
|
+
# Special case for the dash between period dates. It must be
|
|
450
|
+
# surrounded by blanks.
|
|
451
|
+
if (c3 = nextChar) == ' '
|
|
452
|
+
return [ 'LITERAL', ' - ']
|
|
453
|
+
end
|
|
454
|
+
returnChar(c3)
|
|
455
|
+
end
|
|
456
|
+
returnChar(c2)
|
|
457
|
+
elsif c != "\n" && c != "\t"
|
|
458
|
+
returnChar(c)
|
|
459
|
+
return nil
|
|
460
|
+
end
|
|
461
|
+
c = nextChar
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
def readNumber(c)
|
|
466
|
+
token = ""
|
|
467
|
+
token << c
|
|
468
|
+
while ('0'..'9') === (c = nextChar)
|
|
469
|
+
token << c
|
|
470
|
+
end
|
|
471
|
+
if c == '-'
|
|
472
|
+
return readDate(token)
|
|
473
|
+
elsif c == '.'
|
|
474
|
+
frac = readDigits
|
|
475
|
+
|
|
476
|
+
return [ 'FLOAT', token.to_f + frac.to_f / (10.0 ** frac.length) ]
|
|
477
|
+
elsif c == ':'
|
|
478
|
+
hours = token.to_i
|
|
479
|
+
mins = readDigits.to_i
|
|
480
|
+
if hours < 0 || hours > 24
|
|
481
|
+
raise TjException.new, "Hour must be between 0 and 23"
|
|
482
|
+
end
|
|
483
|
+
if mins < 0 || mins > 59
|
|
484
|
+
raise TjException.new, "Minutes must be between 0 and 59"
|
|
485
|
+
end
|
|
486
|
+
if hours == 24 && mins != 0
|
|
487
|
+
raise TjException.new, "Time may not be larger than 24:00"
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# Return time as seconds of day since midnight.
|
|
491
|
+
return [ 'TIME', hours * 60 * 60 + mins * 60 ]
|
|
492
|
+
else
|
|
493
|
+
returnChar(c)
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
[ 'INTEGER', token.to_i ]
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
def readRelativeId(c)
|
|
500
|
+
token = ""
|
|
501
|
+
token << c
|
|
502
|
+
while (c = nextChar) && c == '!'
|
|
503
|
+
token << c
|
|
504
|
+
end
|
|
505
|
+
unless ('a'..'z') === c || ('A'..'Z') === c || c == '_'
|
|
506
|
+
raise TjException.new, "Identifier expected"
|
|
507
|
+
end
|
|
508
|
+
id = readId(c)
|
|
509
|
+
id[0] = 'RELATIVE_ID'
|
|
510
|
+
id[1] = token + id[1]
|
|
511
|
+
id
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
def readDate(token)
|
|
515
|
+
year = token.to_i
|
|
516
|
+
if year < 1970 || year > 2030
|
|
517
|
+
raise TjException.new, "Year must be between 1970 and 2030"
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
month = readDigits.to_i
|
|
521
|
+
if month < 1 || month > 12
|
|
522
|
+
raise TjException.new, "Month must be between 1 and 12"
|
|
523
|
+
end
|
|
524
|
+
if nextChar != '-'
|
|
525
|
+
raise TjException.new, "Corrupted date"
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
day = readDigits.to_i
|
|
529
|
+
if day < 1 || day > 31
|
|
530
|
+
raise TjException.new, "Day must be between 1 and 31"
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
if (c = nextChar) != '-'
|
|
534
|
+
returnChar(c)
|
|
535
|
+
return [ 'DATE', TjTime.local(year, month, day) ]
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
hour = readDigits.to_i
|
|
539
|
+
if hour < 0 || hour > 23
|
|
540
|
+
raise TjException.new, "Hour must be between 0 and 23"
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
if nextChar != ':'
|
|
544
|
+
raise TjException.new, "Corrupted time. ':' expected."
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
minutes = readDigits.to_i
|
|
548
|
+
if minutes < 0 || minutes > 59
|
|
549
|
+
raise TjException.new, "Minutes must be between 0 and 59"
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
if (c = nextChar) == ':'
|
|
553
|
+
seconds = readDigits.to_i
|
|
554
|
+
if seconds < 0 || seconds > 59
|
|
555
|
+
raise TjException.new, "Seconds must be between 0 and 59"
|
|
556
|
+
end
|
|
557
|
+
else
|
|
558
|
+
seconds = 0
|
|
559
|
+
returnChar(c)
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
if (c = nextChar) != '-'
|
|
563
|
+
returnChar(c)
|
|
564
|
+
return [ 'DATE', TjTime.local(year, month, day, hour, minutes, seconds) ]
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
if (c = nextChar) == '-'
|
|
568
|
+
delta = 1
|
|
569
|
+
elsif c == '+'
|
|
570
|
+
delta = -1
|
|
571
|
+
else
|
|
572
|
+
# An actual time zone name
|
|
573
|
+
tz = readId(c)[1]
|
|
574
|
+
oldTz = ENV['TZ']
|
|
575
|
+
ENV['TZ'] = tz
|
|
576
|
+
timeVal = TjTime.local(year, month, day, hour, minutes, seconds)
|
|
577
|
+
ENV['TZ'] = oldTz
|
|
578
|
+
if timeVal.to_a[9] != tz
|
|
579
|
+
raise TjException.new, "Unknown time zone #{tz}"
|
|
580
|
+
end
|
|
581
|
+
return [ 'DATE', timeVal ]
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
utcDiff = readDigits
|
|
585
|
+
utcHour = utcDiff[0, 2].to_i
|
|
586
|
+
if utcHour < 0 || utcHour > 23
|
|
587
|
+
raise TjException.new, "Hour must be between 0 and 23"
|
|
588
|
+
end
|
|
589
|
+
utcMin = utcDiff[2, 2].to_i
|
|
590
|
+
if utcMin < 0 || utcMin > 59
|
|
591
|
+
raise TjException.new, "Minutes must be between 0 and 59"
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
[ 'DATE', TjTime.gm(year, month, day, hour, minutes, seconds) +
|
|
595
|
+
delta * ((utcHour * 3600) + utcMin * 60) ]
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
def readString(terminator)
|
|
599
|
+
token = ""
|
|
600
|
+
while (c = nextChar) && c != terminator
|
|
601
|
+
if c == "\\"
|
|
602
|
+
# Terminators can be used as regular characters when prefixed by a \.
|
|
603
|
+
if (c = nextChar) && c != terminator
|
|
604
|
+
# \ followed by non-terminator. Just add both.
|
|
605
|
+
token << "\\"
|
|
606
|
+
end
|
|
607
|
+
end
|
|
608
|
+
token << c
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
[ 'STRING', token ]
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
def readId(c)
|
|
615
|
+
token = ""
|
|
616
|
+
token << c
|
|
617
|
+
while (c = nextChar) &&
|
|
618
|
+
(('a'..'z') === c || ('A'..'Z') === c || ('0'..'9') === c ||
|
|
619
|
+
c == '_')
|
|
620
|
+
token << c
|
|
621
|
+
end
|
|
622
|
+
if c == ':'
|
|
623
|
+
return [ 'ID_WITH_COLON', token ]
|
|
624
|
+
elsif c == '.'
|
|
625
|
+
token << c
|
|
626
|
+
loop do
|
|
627
|
+
token += readIdentifier
|
|
628
|
+
break if (c = nextChar) != '.'
|
|
629
|
+
token += '.'
|
|
630
|
+
end
|
|
631
|
+
returnChar c
|
|
632
|
+
|
|
633
|
+
return [ 'ABSOLUTE_ID', token ]
|
|
634
|
+
else
|
|
635
|
+
returnChar c
|
|
636
|
+
return [ 'ID', token ]
|
|
637
|
+
end
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
def readMacro
|
|
641
|
+
token = ''
|
|
642
|
+
while (c = nextCharI) != ']'
|
|
643
|
+
error('unterminated_macro', "Unterminated macro #{token}") unless c
|
|
644
|
+
token << c
|
|
645
|
+
end
|
|
646
|
+
return [ 'MACRO', token ]
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
# Read only decimal digits and return the result als Fixnum.
|
|
650
|
+
def readDigits
|
|
651
|
+
token = ""
|
|
652
|
+
while ('0'..'9') === (c = nextChar)
|
|
653
|
+
token << c
|
|
654
|
+
end
|
|
655
|
+
# Make sure that we have read at least one digit.
|
|
656
|
+
if token == ""
|
|
657
|
+
raise TjException.new, "Digit (0 - 9) expected"
|
|
658
|
+
end
|
|
659
|
+
# Push back the non-digit that terminated the digits.
|
|
660
|
+
returnChar(c)
|
|
661
|
+
token
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
def readIdentifier(noDigit = true)
|
|
665
|
+
token = ""
|
|
666
|
+
while (c = nextChar) &&
|
|
667
|
+
(('a'..'z') === c || ('A'..'Z') === c ||
|
|
668
|
+
(!noDigit && (('0'..'9') === c)) || c == '_')
|
|
669
|
+
token << c
|
|
670
|
+
noDigit = false
|
|
671
|
+
end
|
|
672
|
+
returnChar(c)
|
|
673
|
+
if token == ""
|
|
674
|
+
raise TjException.new, "Identifier expected"
|
|
675
|
+
end
|
|
676
|
+
token
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
end
|
|
682
|
+
|