771 return true; |
771 return true; |
772 } |
772 } |
773 |
773 |
774 // ============================================================================= |
774 // ============================================================================= |
775 // |
775 // |
776 class LDParseError : public std::exception |
776 static void checkTokenCount (const QStringList& tokens, int num) |
777 { |
|
778 PROPERTY (private, String, error, setError, STOCK_WRITE) |
|
779 PROPERTY (private, String, line, setLine, STOCK_WRITE) |
|
780 |
|
781 public: |
|
782 LDParseError (String line, String a) : |
|
783 m_error (a), |
|
784 m_line (line) {} |
|
785 |
|
786 const char* what() const throw() |
|
787 { |
|
788 return qPrintable (error()); |
|
789 } |
|
790 }; |
|
791 |
|
792 // ============================================================================= |
|
793 // |
|
794 void checkTokenCount (String line, const QStringList& tokens, int num) |
|
795 { |
777 { |
796 if (tokens.size() != num) |
778 if (tokens.size() != num) |
797 throw LDParseError (line, format ("Bad amount of tokens, expected %1, got %2", num, tokens.size())); |
779 throw String (format ("Bad amount of tokens, expected %1, got %2", num, tokens.size())); |
798 } |
780 } |
799 |
781 |
800 // ============================================================================= |
782 // ============================================================================= |
801 // |
783 // |
802 void checkTokenNumbers (String line, const QStringList& tokens, int min, int max) |
784 static void checkTokenNumbers (const QStringList& tokens, int min, int max) |
803 { |
785 { |
804 bool ok; |
786 bool ok; |
805 |
787 |
806 // Check scientific notation, e.g. 7.99361e-15 |
788 // Check scientific notation, e.g. 7.99361e-15 |
807 QRegExp scient ("\\-?[0-9]+\\.[0-9]+e\\-[0-9]+"); |
789 QRegExp scient ("\\-?[0-9]+\\.[0-9]+e\\-[0-9]+"); |
810 { |
792 { |
811 tokens[i].toDouble (&ok); |
793 tokens[i].toDouble (&ok); |
812 |
794 |
813 if (not ok && not scient.exactMatch (tokens[i])) |
795 if (not ok && not scient.exactMatch (tokens[i])) |
814 { |
796 { |
815 throw LDParseError (line, format ("Token #%1 was `%2`, expected a number (matched length: %3)", |
797 throw String (format ("Token #%1 was `%2`, expected a number (matched length: %3)", |
816 (i + 1), tokens[i], scient.matchedLength())); |
798 (i + 1), tokens[i], scient.matchedLength())); |
817 } |
799 } |
818 } |
800 } |
819 } |
801 } |
820 |
802 |
843 // Line was empty, or only consisted of whitespace |
825 // Line was empty, or only consisted of whitespace |
844 return spawn<LDEmpty>(); |
826 return spawn<LDEmpty>(); |
845 } |
827 } |
846 |
828 |
847 if (tokens[0].length() != 1 || not tokens[0][0].isDigit()) |
829 if (tokens[0].length() != 1 || not tokens[0][0].isDigit()) |
848 throw LDParseError (line, "Illogical line code"); |
830 throw String ("Illogical line code"); |
849 |
831 |
850 int num = tokens[0][0].digitValue(); |
832 int num = tokens[0][0].digitValue(); |
851 |
833 |
852 switch (num) |
834 switch (num) |
853 { |
835 { |
879 { |
861 { |
880 // Handle LDForge-specific types, they're embedded into comments too |
862 // Handle LDForge-specific types, they're embedded into comments too |
881 if (tokens[2] == "VERTEX") |
863 if (tokens[2] == "VERTEX") |
882 { |
864 { |
883 // Vertex (0 !LDFORGE VERTEX) |
865 // Vertex (0 !LDFORGE VERTEX) |
884 checkTokenCount (line, tokens, 7); |
866 checkTokenCount (tokens, 7); |
885 checkTokenNumbers (line, tokens, 3, 6); |
867 checkTokenNumbers (tokens, 3, 6); |
886 |
868 |
887 LDVertexPtr obj = spawn<LDVertex>(); |
869 LDVertexPtr obj = spawn<LDVertex>(); |
888 obj->setColor (tokens[3].toLong()); |
870 obj->setColor (tokens[3].toLong()); |
889 obj->pos.apply ([&](Axis ax, double& value) { value = tokens[4 + ax].toDouble(); }); |
871 obj->pos.apply ([&](Axis ax, double& value) { value = tokens[4 + ax].toDouble(); }); |
890 return obj; |
872 return obj; |
891 } |
873 } |
892 elif (tokens[2] == "OVERLAY") |
874 elif (tokens[2] == "OVERLAY") |
893 { |
875 { |
894 checkTokenCount (line, tokens, 9); |
876 checkTokenCount (tokens, 9); |
895 checkTokenNumbers (line, tokens, 5, 8); |
877 checkTokenNumbers (tokens, 5, 8); |
896 |
878 |
897 LDOverlayPtr obj = spawn<LDOverlay>(); |
879 LDOverlayPtr obj = spawn<LDOverlay>(); |
898 obj->setFileName (tokens[3]); |
880 obj->setFileName (tokens[3]); |
899 obj->setCamera (tokens[4].toLong()); |
881 obj->setCamera (tokens[4].toLong()); |
900 obj->setX (tokens[5].toLong()); |
882 obj->setX (tokens[5].toLong()); |
912 } |
894 } |
913 |
895 |
914 case 1: |
896 case 1: |
915 { |
897 { |
916 // Subfile |
898 // Subfile |
917 checkTokenCount (line, tokens, 15); |
899 checkTokenCount (tokens, 15); |
918 checkTokenNumbers (line, tokens, 1, 13); |
900 checkTokenNumbers (tokens, 1, 13); |
919 |
901 |
920 // Try open the file. Disable g_loadingMainFile temporarily since we're |
902 // Try open the file. Disable g_loadingMainFile temporarily since we're |
921 // not loading the main file now, but the subfile in question. |
903 // not loading the main file now, but the subfile in question. |
922 bool tmp = g_loadingMainFile; |
904 bool tmp = g_loadingMainFile; |
923 g_loadingMainFile = false; |
905 g_loadingMainFile = false; |
947 return obj; |
929 return obj; |
948 } |
930 } |
949 |
931 |
950 case 2: |
932 case 2: |
951 { |
933 { |
952 checkTokenCount (line, tokens, 8); |
934 checkTokenCount (tokens, 8); |
953 checkTokenNumbers (line, tokens, 1, 7); |
935 checkTokenNumbers (tokens, 1, 7); |
954 |
936 |
955 // Line |
937 // Line |
956 LDLinePtr obj (spawn<LDLine>()); |
938 LDLinePtr obj (spawn<LDLine>()); |
957 obj->setColor (tokens[1].toLong()); |
939 obj->setColor (tokens[1].toLong()); |
958 |
940 |
962 return obj; |
944 return obj; |
963 } |
945 } |
964 |
946 |
965 case 3: |
947 case 3: |
966 { |
948 { |
967 checkTokenCount (line, tokens, 11); |
949 checkTokenCount (tokens, 11); |
968 checkTokenNumbers (line, tokens, 1, 10); |
950 checkTokenNumbers (tokens, 1, 10); |
969 |
951 |
970 // Triangle |
952 // Triangle |
971 LDTrianglePtr obj (spawn<LDTriangle>()); |
953 LDTrianglePtr obj (spawn<LDTriangle>()); |
972 obj->setColor (tokens[1].toLong()); |
954 obj->setColor (tokens[1].toLong()); |
973 |
955 |
998 |
980 |
999 return obj; |
981 return obj; |
1000 } |
982 } |
1001 |
983 |
1002 default: |
984 default: |
1003 throw LDParseError (line, "Unknown line code number"); |
985 throw String ("Unknown line code number"); |
1004 } |
986 } |
1005 } |
987 } |
1006 catch (LDParseError& e) |
988 catch (String& e) |
1007 { |
989 { |
1008 // Strange line we couldn't parse |
990 // Strange line we couldn't parse |
1009 return spawn<LDError> (e.line(), e.error()); |
991 return spawn<LDError> (line, e); |
1010 } |
992 } |
1011 } |
993 } |
1012 |
994 |
1013 // ============================================================================= |
995 // ============================================================================= |
1014 // |
996 // |