├── .idea ├── ant.xml └── libraries │ ├── Maven__junit_junit_4_10.xml │ ├── Maven__javax_servlet_jstl_1_2.xml │ ├── Maven__org_jsoup_jsoup_1_7_2.xml │ ├── Maven__org_json_json_20090211.xml │ ├── Maven__joda_time_joda_time_2_1.xml │ ├── Maven__org_joda_joda_money_0_6.xml │ ├── Maven__com_google_guava_guava_14_0_1.xml │ ├── Maven__org_jscience_jscience_4_3_1.xml │ ├── Maven__com_google_code_gson_gson_2_2_2.xml │ ├── Maven__javax_servlet_servlet_api_2_5.xml │ ├── Maven__org_mockito_mockito_all_1_9_0.xml │ ├── Maven__org_hamcrest_hamcrest_core_1_1.xml │ ├── Maven__org_javolution_javolution_5_2_3.xml │ ├── Maven__com_google_gwt_gwt_user_2_5_0_rc1.xml │ ├── Maven__org_functionaljava_functionaljava_3_1.xml │ ├── Maven__com_googlecode_objectify_objectify_4_0b1.xml │ ├── Maven__javax_validation_validation_api_1_0_0_GA.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_core_2_0_6.xml │ ├── Maven__javax_validation_validation_api_sources_1_0_0_GA.xml │ ├── Maven__com_google_appengine_appengine_api_labs_1_7_2.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_databind_2_0_6.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_annotations_2_0_6.xml │ └── Maven__org_apache_geronimo_specs_geronimo_jpa_3_0_spec_1_1_1.xml ├── src ├── main │ ├── webapp │ │ ├── images │ │ │ ├── mind-blown.jpg │ │ │ └── homework-cartoon.gif │ │ ├── WEB-INF │ │ │ ├── appengine-generated │ │ │ │ └── local_db.bin │ │ │ ├── datastore-indexes.xml │ │ │ ├── logging.properties │ │ │ ├── appengine-web.xml │ │ │ └── web.xml │ │ ├── noie.html │ │ ├── js │ │ │ ├── jquery.cookie.js │ │ │ ├── rangy-selectionsaverestore.js │ │ │ └── rangy-serializer.js │ │ └── css │ │ │ ├── highlighting.css │ │ │ └── metal │ │ │ └── style.css │ └── java │ │ └── com │ │ └── lastcalc │ │ ├── bootstrap │ │ └── Bootstrap.java │ │ ├── db │ │ ├── DAO.java │ │ ├── Question.java │ │ ├── User.java │ │ ├── Worksheet.java │ │ └── Line.java │ │ ├── parsers │ │ ├── math │ │ │ ├── ImplicitMultiply.java │ │ │ ├── Radix.java │ │ │ ├── BitwiseOp.java │ │ │ ├── RadixConverter.java │ │ │ ├── GCDLCMParser.java │ │ │ ├── FactorialParser.java │ │ │ ├── IsPrimeParser.java │ │ │ └── PrimesUnderParser.java │ │ ├── collections │ │ │ ├── AppendList.java │ │ │ ├── FoldLeft.java │ │ │ ├── ApplyTo.java │ │ │ ├── Filter.java │ │ │ └── GetFromListOrMap.java │ │ ├── NoopParser.java │ │ ├── ParserContext.java │ │ ├── TrailingEqualsStripper.java │ │ ├── currency │ │ │ ├── CurrencyReverser.java │ │ │ └── Currencies.java │ │ ├── bool │ │ │ ├── BoolFunctionsParser.java │ │ │ ├── BoolParser.java │ │ │ ├── EqualityParser.java │ │ │ ├── NotParser.java │ │ │ └── IfThenElseParser.java │ │ ├── ToLowerCase.java │ │ ├── Interpret.java │ │ ├── amounts │ │ │ ├── UnitStripper.java │ │ │ ├── AmountParser.java │ │ │ └── AmountConverterParser.java │ │ ├── UDPApplier.java │ │ ├── strings │ │ │ └── StringAppender.java │ │ ├── web │ │ │ ├── GetFromElement.java │ │ │ ├── HttpRetriever.java │ │ │ └── Select.java │ │ ├── RewriteParser.java │ │ └── meta │ │ │ └── ImportParser.java │ │ ├── servlets │ │ ├── UserServlet.java │ │ ├── HelpServlet.java │ │ └── StatelessServlet.java │ │ ├── engines │ │ ├── ParseEngine.java │ │ ├── ParserSet.java │ │ ├── FixedOrderParserPickerFactory.java │ │ ├── CombinedParserPickerFactory.java │ │ ├── RecentFirstParserPickerFactory.java │ │ ├── ParseStep.java │ │ ├── BacktrackingParseEngine.java │ │ ├── ParserPickerFactory.java │ │ └── KeywordParserPickerFactory.java │ │ ├── cache │ │ ├── ElementWrapper.java │ │ ├── DocumentWrapper.java │ │ └── ObjectCache.java │ │ ├── Misc.java │ │ └── Tokenizer.java └── test │ └── java │ └── com │ └── lastcalc │ ├── TokenizerTest.java │ ├── parsers │ ├── currency │ │ └── CurrenciesTest.java │ ├── amounts │ │ └── UnitParserTest.java │ ├── PreParserTest.java │ ├── math │ │ ├── FactorialParserTest.java │ │ ├── PrimesUnderTest.java │ │ ├── GCDLCMTest.java │ │ └── IsPrimeTest.java │ ├── bool │ │ └── IfThenElseParserTest.java │ ├── collections │ │ └── CollectionsTest.java │ └── UserDefinedParserParserTest.java │ ├── ParsersTest.java │ ├── engines │ └── CombinedParserPickerFactoryTest.java │ └── servlets │ └── WorksheetServletTest.java ├── .settings ├── com.google.gdt.eclipse.core.prefs └── com.google.appengine.eclipse.core.prefs ├── .gitignore ├── .travis.yml ├── README.markdown ├── .project └── .classpath /.idea/ant.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/webapp/images/mind-blown.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity/LastCalc/HEAD/src/main/webapp/images/mind-blown.jpg -------------------------------------------------------------------------------- /src/main/webapp/images/homework-cartoon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity/LastCalc/HEAD/src/main/webapp/images/homework-cartoon.gif -------------------------------------------------------------------------------- /.settings/com.google.gdt.eclipse.core.prefs: -------------------------------------------------------------------------------- 1 | #Fri Dec 09 10:46:02 CST 2011 2 | eclipse.preferences.version=1 3 | warSrcDir=war 4 | warSrcDirIsOutput=true 5 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/appengine-generated/local_db.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanity/LastCalc/HEAD/src/main/webapp/WEB-INF/appengine-generated/local_db.bin -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | war/WEB-INF/appengine-generated 3 | war/WEB-INF/classes 4 | test-output/ 5 | annotations/ 6 | .idea/ 7 | .settings/ 8 | target/ 9 | *.iml 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | after_success:sudo: false 2 | language: java 3 | notifications: 4 | email: 5 | - ian.clarke@gmail.com 6 | - oliverlee010@gmail.com 7 | after_success: 8 | - mvn clean cobertura:cobertura coveralls:report 9 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | SourceCode for [LastCalc.com](http://lastcalc.com/). 2 | 3 | Please see [the wiki](https://github.com/sanity/LastCalc/wiki) for further information about how LastCalc works internally, and a guide to contributing to LastCalc. 4 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/datastore-indexes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__junit_junit_4_10.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/logging.properties: -------------------------------------------------------------------------------- 1 | # A default java.util.logging configuration. 2 | # (All App Engine logging is through java.util.logging by default). 3 | # 4 | # To use this configuration, copy it into your application's WEB-INF 5 | # folder and add the following to your appengine-web.xml: 6 | # 7 | # 8 | # 9 | # 10 | # 11 | 12 | # Set the default logging level for all loggers to WARNING 13 | .level = WARNING 14 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_servlet_jstl_1_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.settings/com.google.appengine.eclipse.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | filesCopiedToWebInfLib=appengine-api-labs.jar|appengine-endpoints.jar|appengine-jsr107cache-1.7.1.jar|jsr107cache-1.1.jar|appengine-api-1.0-sdk-1.7.1.jar|datanucleus-appengine-1.0.10.final.jar|datanucleus-core-1.1.5.jar|datanucleus-jpa-1.1.5.jar|geronimo-jpa_3.0_spec-1.1.1.jar|geronimo-jta_1.1_spec-1.1.1.jar|jdo2-api-2.3-eb.jar 3 | gaeDeployDialogSettings= 4 | gaeHrdEnabled=true 5 | gaeIsEclipseDefaultInstPath=false 6 | googleCloudSqlEnabled=false 7 | localDevMySqlEnabled=true 8 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_jsoup_jsoup_1_7_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_json_json_20090211.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__joda_time_joda_time_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_joda_joda_money_0_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_guava_guava_14_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_jscience_jscience_4_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_code_gson_gson_2_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_servlet_servlet_api_2_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mockito_mockito_all_1_9_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_javolution_javolution_5_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_gwt_gwt_user_2_5_0_rc1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | lastcalc 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_functionaljava_functionaljava_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_googlecode_objectify_objectify_4_0b1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_validation_validation_api_1_0_0_GA.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_0_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_validation_validation_api_sources_1_0_0_GA.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/webapp/noie.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | LastCalc: Your browser is not supported :-( 4 | 5 | 6 | 7 |

Your browser is not yet supported

8 | Due to your web browser's incomplete support for modern web standards, we're afraid 9 | that LastCalc will not yet work with it. We hope to sort out these issues soon, 10 | but in the meantime we recommend that you use 11 | Google Chrome. 12 |

13 | LastCalc is also compatible with Firefox and 14 | Safari. 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_appengine_appengine_api_labs_1_7_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/appengine-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | lastcalc-upr 4 | 1 5 | 6 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | true 19 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_0_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_0_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_geronimo_specs_geronimo_jpa_3_0_spec_1_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/bootstrap/Bootstrap.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.bootstrap; 17 | 18 | public class Bootstrap { 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/TokenizerTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc; 17 | 18 | 19 | public class TokenizerTest { 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/db/DAO.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.db; 17 | 18 | import com.googlecode.objectify.*; 19 | 20 | public class DAO { 21 | 22 | static { 23 | ObjectifyService.register(Worksheet.class); 24 | } 25 | 26 | public static Objectify begin() { 27 | return ObjectifyService.ofy(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/currency/CurrenciesTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.currency; 17 | 18 | import org.junit.Test; 19 | 20 | public class CurrenciesTest { 21 | 22 | @Test 23 | public void test() { 24 | Currencies.updateExchangeRates(); 25 | 26 | System.out.println(Currencies.currenciesByCode); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/amounts/UnitParserTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.amounts; 17 | 18 | import java.util.Set; 19 | 20 | import org.junit.Test; 21 | 22 | public class UnitParserTest { 23 | 24 | @Test 25 | public void test() { 26 | final Set parsers = UnitParser.getParsers(); 27 | System.out.println(parsers); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/ParsersTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc; 17 | 18 | import org.junit.Test; 19 | 20 | public class ParsersTest { 21 | 22 | @Test 23 | public void testTokenize() { 24 | final String test1 = "one=15+(3/7.8)*12,533 + average of [1, 2...[3]]"; 25 | final TokenList test1t = Tokenizer.tokenize(test1); 26 | for (final Object o : test1t) { 27 | System.out.println(o); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/db/Question.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.db; 17 | 18 | import com.googlecode.objectify.annotation.Entity; 19 | import com.googlecode.objectify.annotation.Unindex; 20 | 21 | import javax.persistence.Id; 22 | 23 | @Entity 24 | public class Question { 25 | @Id 26 | public long id; 27 | 28 | public int position; 29 | 30 | public String worksheet; 31 | 32 | @Unindex 33 | public String question; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/math/ImplicitMultiply.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.math; 2 | 3 | import com.lastcalc.TokenList; 4 | import com.lastcalc.parsers.Parser; 5 | 6 | /** 7 | * Created by ian on 5/31/15. 8 | */ 9 | public class ImplicitMultiply extends Parser { 10 | private static TokenList template = TokenList.createD(org.jscience.mathematics.number.Number.class, org.jscience.mathematics.number.Number.class); 11 | 12 | @Override 13 | public TokenList getTemplate() { 14 | return template; 15 | } 16 | 17 | @Override 18 | public int hashCode() { 19 | return "ImplicitMultiply".hashCode(); 20 | } 21 | 22 | @Override 23 | public ParseResult parse(TokenList tokens, int templatePos) { 24 | Number number1 = (Number) tokens.get(templatePos); 25 | Number number2 = (Number) tokens.get(templatePos + 1); 26 | 27 | TokenList.CompositeTokenList newTokens = tokens.replaceWithTokens(templatePos, templatePos + 2, number1, "*", number2); 28 | // Add a score bias so that "twenty five" is parsed as "20+5" and not "20*5" 29 | return ParseResult.success(newTokens, 1); 30 | } 31 | 32 | @Override 33 | public boolean equals(Object obj) { 34 | return obj instanceof ImplicitMultiply; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/db/User.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.db; 17 | 18 | import com.googlecode.objectify.annotation.Cache; 19 | import com.googlecode.objectify.annotation.Unindex; 20 | 21 | import javax.persistence.Id; 22 | 23 | @Cache 24 | public class User { 25 | public static final String passwordSalt = "5pDTVGeciETDWwy"; 26 | 27 | @Id 28 | public long id; 29 | 30 | public String cookieId; 31 | 32 | public String username; 33 | 34 | public String email; 35 | 36 | @Unindex 37 | public String saltedPasswordHash; 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/collections/AppendList.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.collections; 2 | 3 | import com.google.appengine.labs.repackaged.com.google.common.collect.Lists; 4 | import com.lastcalc.TokenList; 5 | import com.lastcalc.parsers.Parser; 6 | import com.lastcalc.parsers.ParserContext; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Created by ian on 6/2/15. 12 | */ 13 | public class AppendList extends Parser { 14 | private static TokenList template = TokenList.createD(List.class, Lists.newArrayList("append", "+"), List.class); 15 | 16 | @Override 17 | public TokenList getTemplate() { 18 | return template; 19 | } 20 | 21 | @Override 22 | public int hashCode() { 23 | return "AppendList".hashCode(); 24 | } 25 | 26 | @Override 27 | public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) { 28 | List list1 = (List) tokens.get(templatePos); 29 | List list2 = (List) tokens.get(templatePos+2); 30 | List newList = Lists.newArrayList(); 31 | newList.addAll(list1); 32 | newList.addAll(list2); 33 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos+3, newList)); 34 | } 35 | 36 | @Override 37 | public boolean equals(Object obj) { 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | MainPage 9 | com.lastcalc.servlets.MainPageServlet 10 | 11 | 12 | Worksheet 13 | com.lastcalc.servlets.WorksheetServlet 14 | 15 | 16 | Stateless 17 | com.lastcalc.servlets.StatelessServlet 18 | 19 | 20 | Help 21 | com.lastcalc.servlets.HelpServlet 22 | 23 | 24 | MainPage 25 | /* 26 | 27 | 28 | Worksheet 29 | /ws 30 | 31 | 32 | Stateless 33 | /sl 34 | 35 | 36 | Help 37 | /help 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/servlets/UserServlet.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.servlets; 17 | 18 | import javax.servlet.http.HttpServlet; 19 | 20 | public class UserServlet extends HttpServlet { 21 | private static final long serialVersionUID = 8713053995956225568L; 22 | 23 | @Override 24 | protected void doPost(final javax.servlet.http.HttpServletRequest req, 25 | final javax.servlet.http.HttpServletResponse resp) throws javax.servlet.ServletException, 26 | java.io.IOException { 27 | } 28 | 29 | public static class UserServletRequest { 30 | public String username, saltedPasswordHash; 31 | 32 | public RegisterRequest register; 33 | } 34 | 35 | public static class RegisterRequest { 36 | public String email; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/NoopParser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers; 17 | 18 | import com.lastcalc.TokenList; 19 | 20 | public class NoopParser extends Parser { 21 | private static final long serialVersionUID = 7600767637692555261L; 22 | public static final NoopParser singleton = new NoopParser(); 23 | 24 | @Override 25 | public TokenList getTemplate() { 26 | return null; 27 | } 28 | 29 | @Override 30 | public ParseResult parse(final TokenList tokens, final int templatePos) { 31 | return ParseResult.success(tokens); 32 | } 33 | 34 | @Override 35 | public int hashCode() { 36 | return "NoopParser".hashCode(); 37 | } 38 | 39 | @Override 40 | public boolean equals(final Object obj) { 41 | return obj instanceof NoopParser; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/ParserContext.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers; 17 | 18 | import com.lastcalc.engines.ParseEngine; 19 | 20 | public class ParserContext implements Cloneable { 21 | public final ParseEngine parseEngine; 22 | 23 | public int importDepth = 0; 24 | 25 | public long timeout; 26 | 27 | public ParserContext(final ParseEngine parseEngine, final long timeout, final int importDepth) { 28 | this(parseEngine, timeout); 29 | this.importDepth = importDepth; 30 | } 31 | 32 | public ParserContext(final ParseEngine parseEngine, final long timeout) { 33 | this.parseEngine = parseEngine; 34 | this.timeout = timeout; 35 | } 36 | 37 | @Override 38 | public Object clone() throws CloneNotSupportedException { 39 | return super.clone(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/engines/ParseEngine.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.engines; 17 | 18 | import java.util.LinkedList; 19 | 20 | import com.lastcalc.TokenList; 21 | import com.lastcalc.parsers.ParserContext; 22 | 23 | 24 | public abstract class ParseEngine { 25 | 26 | public TokenList parseAndGetLastStep(final TokenList input, 27 | final ParserContext context, 28 | final TokenList... alternateInputs) { 29 | final LinkedList parse = parse(input, context, alternateInputs); 30 | if (parse.isEmpty()) 31 | throw new RuntimeException("Parse resulted in no ParseSteps"); 32 | return parse.getLast().result.output; 33 | } 34 | 35 | public abstract LinkedList parse(final TokenList input, 36 | ParserContext context, 37 | TokenList... alternateInputs); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/servlets/HelpServlet.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.servlets; 17 | 18 | import java.io.IOException; 19 | 20 | import javax.servlet.ServletException; 21 | import javax.servlet.http.*; 22 | 23 | import com.lastcalc.lessons.Help; 24 | 25 | public class HelpServlet extends HttpServlet { 26 | private static final long serialVersionUID = -7706942563225877578L; 27 | 28 | @Override 29 | public void init() throws javax.servlet.ServletException { 30 | // Force static initialization 31 | Help.lessons.size(); 32 | }; 33 | 34 | @Override 35 | protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, 36 | IOException { 37 | resp.setContentType("text/html; charset=UTF-8"); 38 | resp.setCharacterEncoding("UTF-8"); 39 | resp.getWriter().append(Help.getHelpDoc().toString()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/engines/ParserSet.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.engines; 2 | 3 | import java.util.*; 4 | 5 | import com.lastcalc.parsers.*; 6 | import com.lastcalc.parsers.UserDefinedParserParser.UserDefinedParser; 7 | 8 | /** 9 | * A set for parsers where the UserDefinedParser that shortens the token 10 | * list most comes first. For use in ParserPickerFactories. 11 | * 12 | * @author Ian Clarke 13 | * 14 | */ 15 | public class ParserSet extends TreeSet { 16 | private static final long serialVersionUID = -6285593762627218550L; 17 | 18 | public ParserSet() { 19 | super(new Comparator() { 20 | 21 | @Override 22 | public int compare(final Parser o1, final Parser o2) { 23 | if (o1 instanceof UserDefinedParser && !(o2 instanceof UserDefinedParser)) 24 | return -1; 25 | else if (o2 instanceof UserDefinedParser && !(o1 instanceof UserDefinedParser)) 26 | return 1; 27 | else if (o1 instanceof UserDefinedParser && o2 instanceof UserDefinedParser) { 28 | final UserDefinedParser udp1 = (UserDefinedParser) o1; 29 | final UserDefinedParser udp2 = (UserDefinedParser) o2; 30 | final int sizeRed1 = udp1.after.size() - udp1.getTemplate().size(); 31 | final int sizeRed2 = udp2.after.size() - udp2.getTemplate().size(); 32 | return compareInts(sizeRed1, sizeRed2, compareInts(o1.hashCode(), o2.hashCode(), 0)); 33 | } 34 | else 35 | return compareInts(o1.hashCode(), o2.hashCode(), 0); 36 | } 37 | 38 | }); 39 | } 40 | 41 | private static int compareInts(final int a, final int b, final int otherwise) { 42 | if (ab) return 1; 44 | else return otherwise; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/PreParserTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers; 17 | 18 | import junit.framework.Assert; 19 | 20 | import org.junit.Test; 21 | 22 | import com.lastcalc.*; 23 | 24 | public class PreParserTest { 25 | @Test 26 | public void findObjectTest() { 27 | final TokenList tl = Tokenizer.tokenize("i wish (i was) a tea pot"); 28 | Assert.assertEquals(tl.indexOf("wish"), PreParser.findEdgeOrObjectForwards(tl, tl.indexOf("i"), "wish")); 29 | Assert.assertEquals(tl.size() - 1, PreParser.findEdgeOrObjectForwards(tl, tl.indexOf("i"), "i")); 30 | Assert.assertEquals(0, PreParser.findEdgeOrObjectBackwards(tl, tl.indexOf("pot"), "i")); 31 | Assert.assertEquals(tl.indexOf("(") + 1, PreParser.findEdgeOrObjectBackwards(tl, tl.indexOf("was"), null)); 32 | Assert.assertEquals(tl.size() - 1, PreParser.findEdgeOrObjectForwards(tl, tl.indexOf("wish"), null)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/math/FactorialParserTest.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.math; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.jscience.mathematics.number.LargeInteger; 6 | import org.junit.Test; 7 | 8 | import com.lastcalc.SequentialParser; 9 | import com.lastcalc.TokenList; 10 | import com.lastcalc.parsers.Parser; 11 | import com.lastcalc.parsers.Parser.ParseResult; 12 | 13 | public class FactorialParserTest { 14 | 15 | @Test 16 | public void successfulParseTest(){ 17 | 18 | final FactorialParser fp = new FactorialParser(); 19 | ParseResult pr=fp.parse(TokenList.createD("blah","factorial",LargeInteger.valueOf(3),"blah"),1); 20 | Assert.assertTrue("Ensure parse was succcesful", pr.isSuccess()); 21 | Assert.assertEquals("Ensure parse result is what it's supposed to be",TokenList.createD("blah",LargeInteger.valueOf(6),"blah"), pr.output); 22 | } 23 | 24 | 25 | @Test 26 | public void tooBigOrSmallTest(){ 27 | 28 | final FactorialParser fp = new FactorialParser(); 29 | ParseResult pr=fp.parse(TokenList.createD("blah","factorial",LargeInteger.valueOf(-1),"blah"),1); 30 | Assert.assertFalse("Ensure parse failed b/c it's a negative num", pr.isSuccess()); 31 | 32 | ParseResult pr2=fp.parse(TokenList.createD("blah","factorial",LargeInteger.valueOf(20),"blah"),1); 33 | Assert.assertFalse("Ensure parse failed b/c it's a too big", pr2.isSuccess()); 34 | 35 | } 36 | 37 | public void hookedUpProperly(){ 38 | 39 | final SequentialParser sp=SequentialParser.create(); 40 | 41 | TokenList pr=sp.parseNext(TokenList.createD("6","!")); 42 | 43 | Assert.assertEquals(1,pr.size()); 44 | Assert.assertEquals(LargeInteger.valueOf(720), pr.get(0)); 45 | 46 | } 47 | 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/TrailingEqualsStripper.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers; 17 | 18 | import com.lastcalc.TokenList; 19 | 20 | public class TrailingEqualsStripper extends Parser { 21 | private static final TokenList template = TokenList.createD("="); 22 | private static final long serialVersionUID = 2340131974673871340L; 23 | 24 | @Override 25 | public TokenList getTemplate() { 26 | return template; 27 | } 28 | 29 | @Override 30 | public int hashCode() { 31 | return "TrailingEqualsStripper".hashCode(); 32 | } 33 | 34 | @Override 35 | public ParseResult parse(final TokenList tokens, final int templatePos) { 36 | if (templatePos == tokens.size()-1) 37 | return ParseResult.success(tokens.subList(0, tokens.size() - 1)); 38 | else 39 | return ParseResult.fail(); 40 | } 41 | 42 | @Override 43 | public boolean equals(final Object obj) { 44 | return obj instanceof TrailingEqualsStripper; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/bool/IfThenElseParserTest.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.bool; 2 | 3 | import com.lastcalc.TokenList; 4 | import com.lastcalc.parsers.Parser; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | /** 9 | * Created by ian on 6/3/15. 10 | */ 11 | public class IfThenElseParserTest { 12 | @Test 13 | public void ifThenElseTrueTest() { 14 | IfThenElseParser ifThenElseParser = new IfThenElseParser(); 15 | TokenList trueTL = TokenList.createD("(", "if", Boolean.TRUE, "then", 1, "else", 0, ")"); 16 | Parser.ParseResult trueResult = ifThenElseParser.parse(trueTL, 1); 17 | Assert.assertTrue(trueResult.isSuccess()); 18 | Assert.assertEquals(TokenList.createD("(", 1, ")"), trueResult.output); 19 | 20 | TokenList falseTL = TokenList.createD("(", "if", Boolean.FALSE, "then", 1, "else", 0, ")"); 21 | Parser.ParseResult falseResult = ifThenElseParser.parse(falseTL, 1); 22 | Assert.assertTrue(falseResult.isSuccess()); 23 | Assert.assertEquals(TokenList.createD("(", 0, ")"), falseResult.output); 24 | } 25 | 26 | @Test 27 | public void ifThenTest() { 28 | IfThenElseParser ifThenElseParser = new IfThenElseParser(); 29 | TokenList trueTL = TokenList.createD("(", "if", Boolean.TRUE, "then", 1, ")"); 30 | Parser.ParseResult trueResult = ifThenElseParser.parse(trueTL, 1); 31 | Assert.assertTrue(trueResult.isSuccess()); 32 | Assert.assertEquals(TokenList.createD("(", 1, ")"), trueResult.output); 33 | 34 | TokenList falseTL = TokenList.createD("(", "if", Boolean.FALSE, "then", 1, ")"); 35 | Parser.ParseResult falseResult = ifThenElseParser.parse(falseTL, 1); 36 | Assert.assertFalse(falseResult.isSuccess()); 37 | } 38 | } -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/math/PrimesUnderTest.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.math; 2 | 3 | import com.google.appengine.labs.repackaged.com.google.common.collect.Lists; 4 | import com.lastcalc.TokenList; 5 | import com.lastcalc.parsers.Parser; 6 | import junit.framework.Assert; 7 | import org.jscience.mathematics.number.LargeInteger; 8 | import org.junit.Test; 9 | 10 | import java.util.ArrayList; 11 | 12 | /** 13 | * **************************************************************************** 14 | * LastCalc - The last calculator you'll ever need 15 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 16 | *

17 | * This program is free software: you can redistribute it and/or modify it 18 | * under the terms of the GNU Affero General Public License as published 19 | * by the Free Software Foundation, either version 3 of the License, or 20 | * (at your option) any later version. 21 | *

22 | * This program is distributed in the hope that it will be useful, but 23 | * WITHOUT ANY WARRANTY; without even the implied warranty of 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 25 | * PURPOSE. See the GNU Affero General Public License for more 26 | * details. 27 | * **************************************************************************** 28 | */ 29 | public class PrimesUnderTest { 30 | 31 | 32 | 33 | @Test 34 | public void primesUnderTest(){ 35 | 36 | final PrimesUnderParser pup = new PrimesUnderParser(); 37 | Parser.ParseResult pr=pup.parse(TokenList.createD("blah", "primesunder", LargeInteger.valueOf(3), "blah"),1); 38 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 39 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", Lists.newArrayList(2,3),"blah"), pr.output); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/currency/CurrencyReverser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.currency; 17 | 18 | import org.jscience.economics.money.Currency; 19 | 20 | import com.lastcalc.TokenList; 21 | import com.lastcalc.parsers.Parser; 22 | 23 | public class CurrencyReverser extends Parser { 24 | 25 | public static TokenList template = TokenList.createD(Currency.class, Number.class); 26 | 27 | @Override 28 | public ParseResult parse(final TokenList tokens, final int templatePos) { 29 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), 30 | tokens.get(templatePos + 1), tokens.get(templatePos)), -1); 31 | } 32 | 33 | @Override 34 | public TokenList getTemplate() { 35 | return template; 36 | } 37 | 38 | @Override 39 | public int hashCode() { 40 | return "CurrencyReverser".hashCode(); 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return ""; 46 | } 47 | 48 | @Override 49 | public boolean equals(final Object obj) { 50 | return obj instanceof CurrencyReverser; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/bool/BoolFunctionsParser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.bool; 17 | 18 | import com.google.common.collect.Lists; 19 | 20 | import com.lastcalc.TokenList; 21 | import com.lastcalc.parsers.Parser; 22 | 23 | public class BoolFunctionsParser extends Parser { 24 | private static final long serialVersionUID = -7820633700412274072L; 25 | private static TokenList template = TokenList.createD(Lists.newArrayList("not", "!"), 26 | Boolean.class); 27 | 28 | @Override 29 | public ParseResult parse(final TokenList tokens, final int templatePos) { 30 | final boolean a = (Boolean) tokens.get(templatePos + 1); 31 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), !a)); 32 | } 33 | 34 | @Override 35 | public TokenList getTemplate() { 36 | return template; 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return "BoolFunctionsParser".hashCode(); 42 | } 43 | 44 | @Override 45 | public boolean equals(final Object obj) { 46 | return obj instanceof BoolFunctionsParser; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/bool/BoolParser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.bool; 17 | 18 | import com.google.common.collect.Lists; 19 | 20 | import com.lastcalc.TokenList; 21 | import com.lastcalc.parsers.Parser; 22 | 23 | 24 | public class BoolParser extends Parser { 25 | private static final long serialVersionUID = -7666856639055196045L; 26 | private static TokenList template = TokenList.createD(Lists.newArrayList("true", "yes", "false", "no")); 27 | 28 | 29 | @Override 30 | public TokenList getTemplate() { 31 | return template; 32 | } 33 | 34 | @Override 35 | public ParseResult parse(final TokenList tokens, final int templatePos) { 36 | final boolean result = (tokens.get(templatePos).equals("true") || tokens.get(templatePos).equals("yes")); 37 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), result)); 38 | } 39 | 40 | @Override 41 | public int hashCode() { 42 | return "BoolParser".hashCode(); 43 | } 44 | 45 | @Override 46 | public boolean equals(final Object obj) { 47 | return obj instanceof BoolParser; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/math/Radix.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.math; 17 | 18 | import java.io.Serializable; 19 | 20 | 21 | public class Radix implements Serializable { 22 | private static final long serialVersionUID = 6793205833102927654L; 23 | public final long integer; 24 | public final int radix; 25 | 26 | public static Radix parse(final String value) { 27 | if (value.startsWith("0x")) 28 | return new Radix(Long.parseLong(value.substring(2), 16), 16); 29 | else if (value.startsWith("0b")) 30 | return new Radix(Long.parseLong(value.substring(2), 2), 2); 31 | else if (value.startsWith("0o")) 32 | return new Radix(Long.parseLong(value.substring(2), 8), 8); 33 | else 34 | return null; 35 | } 36 | 37 | public Radix(final long integer, final int radix) { 38 | this.integer = integer; 39 | this.radix = radix; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | String prefix; 45 | if (radix == 2) { 46 | prefix = "0b"; 47 | } else if (radix == 8) { 48 | prefix = "0o"; 49 | } else { 50 | prefix = "0x"; 51 | } 52 | return prefix + Long.toString(integer, radix); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/ToLowerCase.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers; 17 | 18 | import com.lastcalc.TokenList; 19 | 20 | public class ToLowerCase extends Parser { 21 | private static final long serialVersionUID = 4507416694168613210L; 22 | 23 | private static TokenList template = TokenList.createD(String.class); 24 | 25 | @Override 26 | public TokenList getTemplate() { 27 | return template; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return ""; 33 | } 34 | 35 | @Override 36 | public ParseResult parse(final TokenList tokens, final int templatePos) { 37 | final String orig = (String) tokens.get(templatePos); 38 | final String lowerCase = orig.toLowerCase(); 39 | if (!lowerCase.equals(orig)) 40 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), lowerCase), 41 | 0.5); 42 | else 43 | return ParseResult.fail(); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return "ToLowerCase".hashCode(); 49 | } 50 | 51 | @Override 52 | public boolean equals(final Object obj) { 53 | return obj instanceof ToLowerCase; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/math/BitwiseOp.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.math; 2 | 3 | import com.google.common.collect.Lists; 4 | 5 | import org.jscience.mathematics.number.LargeInteger; 6 | 7 | import com.lastcalc.TokenList; 8 | import com.lastcalc.parsers.Parser; 9 | 10 | public class BitwiseOp extends Parser { 11 | private static final long serialVersionUID = -694604478564851560L; 12 | private final TokenList template = TokenList.createD(Lists.newArrayList(LargeInteger.class, Radix.class), 13 | Lists.newArrayList("xor", "and", "or"), Lists.newArrayList(LargeInteger.class, Radix.class)); 14 | 15 | @Override 16 | public TokenList getTemplate() { 17 | return template; 18 | } 19 | 20 | @Override 21 | public ParseResult parse(final TokenList tokens, final int templatePos) { 22 | final Object ar = tokens.get(templatePos); 23 | final long a = ar instanceof LargeInteger ? ((LargeInteger) ar).longValue() : ((Radix) ar).integer; 24 | final String op = (String) tokens.get(templatePos + 1); 25 | final Object br = tokens.get(templatePos + 2); 26 | final long b = br instanceof LargeInteger ? ((LargeInteger) br).longValue() : ((Radix) br).integer; 27 | int radix = 10; 28 | if (ar instanceof Radix && br instanceof Radix && ((Radix) ar).radix == ((Radix) br).radix) { 29 | radix = ((Radix) ar).radix; 30 | } 31 | long result; 32 | if (op.equals("xor")) { 33 | result = a ^ b; 34 | } else if (op.equals("and")) { 35 | result = a & b; 36 | } else if (op.equals("or")) { 37 | result = a | b; 38 | } else 39 | return ParseResult.fail(); 40 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), 41 | radix == 10 ? LargeInteger.valueOf(result) : new Radix(result, radix))); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return "BitwiseOp".hashCode(); 47 | } 48 | 49 | @Override 50 | public boolean equals(final Object obj) { 51 | return obj instanceof BitwiseOp; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/Interpret.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers; 17 | 18 | import com.lastcalc.*; 19 | import com.lastcalc.Tokenizer.QuotedString; 20 | 21 | public class Interpret extends Parser { 22 | private static final long serialVersionUID = 4507416694168613210L; 23 | 24 | private static TokenList template = TokenList.createD("interpret", Tokenizer.QuotedString.class); 25 | 26 | @Override 27 | public TokenList getTemplate() { 28 | return template; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return ""; 34 | } 35 | 36 | @Override 37 | public ParseResult parse(final TokenList tokens, final int templatePos) { 38 | final Tokenizer.QuotedString string = (QuotedString) tokens.get(templatePos + 1); 39 | final TokenList ret = Tokenizer.tokenize(string.value); 40 | return ParseResult.success(tokens.replaceWithTokenList(templatePos, templatePos + template.size(), ret), 41 | -ret.size()); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return "ToLowerCase".hashCode(); 47 | } 48 | 49 | @Override 50 | public boolean equals(final Object obj) { 51 | return obj instanceof Interpret; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/amounts/UnitStripper.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.amounts; 17 | 18 | import javax.measure.unit.Unit; 19 | 20 | import org.jscience.physics.amount.Amount; 21 | 22 | import com.lastcalc.TokenList; 23 | import com.lastcalc.parsers.Parser; 24 | 25 | 26 | public class UnitStripper extends Parser { 27 | private static final long serialVersionUID = 5689741343269900107L; 28 | private static final TokenList template = TokenList.createD(Amount.class); 29 | 30 | @Override 31 | public TokenList getTemplate() { 32 | return template; 33 | } 34 | 35 | @Override 36 | public ParseResult parse(final TokenList tokens, final int templatePos) { 37 | final Amount amount = (Amount) tokens.get(templatePos); 38 | if (amount.getUnit().equals(Unit.ONE)) 39 | return ParseResult.fail(); 40 | return ParseResult.success( 41 | tokens.replaceWithTokens(templatePos, templatePos + template.size(), 42 | Amount.valueOf(amount.getEstimatedValue(), Unit.ONE)), 2); 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | return "UnitStripper".hashCode(); 48 | } 49 | 50 | @Override 51 | public boolean equals(final Object obj) { 52 | return obj instanceof UnitStripper; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/bool/EqualityParser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.bool; 17 | 18 | import com.google.common.collect.Lists; 19 | 20 | import com.lastcalc.TokenList; 21 | import com.lastcalc.parsers.Parser; 22 | 23 | public class EqualityParser extends Parser { 24 | private static final long serialVersionUID = -2750832188085003939L; 25 | private static TokenList template = TokenList.createD(Object.class, Lists.newArrayList("==", "!="), Object.class); 26 | 27 | @Override 28 | public ParseResult parse(final TokenList tokens, final int templatePos) { 29 | final Object a = tokens.get(templatePos); 30 | final String op = (String) tokens.get(templatePos + 1); 31 | final Object b = tokens.get(templatePos + 2); 32 | final boolean result = op.equals("==") ? a.equals(b) : !a.equals(b); 33 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), result)); 34 | } 35 | 36 | @Override 37 | public TokenList getTemplate() { 38 | return template; 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | return "EqualityParser".hashCode(); 44 | } 45 | 46 | @Override 47 | public boolean equals(final Object obj) { 48 | return obj instanceof EqualityParser; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/db/Worksheet.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.db; 17 | 18 | import com.google.common.collect.Lists; 19 | import com.googlecode.objectify.annotation.Cache; 20 | import com.googlecode.objectify.annotation.Entity; 21 | import com.googlecode.objectify.annotation.Id; 22 | import com.googlecode.objectify.annotation.Serialize; 23 | import com.lastcalc.Misc; 24 | import com.lastcalc.parsers.Parser; 25 | 26 | import javax.persistence.PrePersist; 27 | import java.util.ArrayList; 28 | import java.util.Collection; 29 | import java.util.Date; 30 | 31 | @Cache 32 | @Entity 33 | public class Worksheet { 34 | 35 | public Worksheet() { 36 | id = Misc.randomString(7); 37 | readOnlyId = Misc.randomString(8); 38 | qaPairs = Lists.newArrayList(); 39 | created = new Date(); 40 | } 41 | 42 | @Id 43 | public String id; 44 | 45 | public String parentId; 46 | 47 | public String readOnlyId; 48 | 49 | public String description; 50 | 51 | public boolean used; 52 | 53 | @Serialize 54 | public ArrayList qaPairs; 55 | 56 | @Serialize 57 | public Collection definedParsers; 58 | 59 | public Date created, lastModified; 60 | 61 | @PrePersist 62 | private void prePersist() { 63 | lastModified = new Date(); 64 | used = qaPairs.size() > 0; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/webapp/js/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery Cookie plugin 3 | * 4 | * Copyright (c) 2010 Klaus Hartl (stilbuero.de) 5 | * Dual licensed under the MIT and GPL licenses: 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * http://www.gnu.org/licenses/gpl.html 8 | * 9 | */ 10 | (function($) { 11 | $.cookie = function(key, value, options) { 12 | 13 | // key and at least value given, set cookie... 14 | if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) { 15 | options = $.extend({}, options); 16 | 17 | if (value === null || value === undefined) { 18 | options.expires = -1; 19 | } 20 | 21 | if (typeof options.expires === 'number') { 22 | var days = options.expires, t = options.expires = new Date(); 23 | t.setDate(t.getDate() + days); 24 | } 25 | 26 | value = String(value); 27 | 28 | return (document.cookie = [ 29 | encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value), 30 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 31 | options.path ? '; path=' + options.path : '', 32 | options.domain ? '; domain=' + options.domain : '', 33 | options.secure ? '; secure' : '' 34 | ].join('')); 35 | } 36 | 37 | // key and possibly options given, get cookie... 38 | options = value || {}; 39 | var decode = options.raw ? function(s) { return s; } : decodeURIComponent; 40 | 41 | var pairs = document.cookie.split('; '); 42 | for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) { 43 | if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined 44 | } 45 | return null; 46 | }; 47 | })(jQuery); 48 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/cache/ElementWrapper.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.cache; 17 | 18 | import java.io.*; 19 | 20 | import org.jsoup.Jsoup; 21 | import org.jsoup.nodes.Element; 22 | 23 | // Turns out Document has a crappy hashCode() implementation, 24 | // this makes it more efficient 25 | public class ElementWrapper implements Serializable { 26 | public Element el; 27 | 28 | String asString; 29 | 30 | private int hashCode; 31 | 32 | public ElementWrapper(final Element el) { 33 | this.el = el; 34 | asString = el.toString(); 35 | hashCode = asString.hashCode(); 36 | 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return hashCode; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | if (asString.length() < 60) 47 | return asString; 48 | else 49 | return "<" + el.tagName() + " - too big (" + asString.length() + " chars)>"; 50 | } 51 | 52 | private void writeObject(final ObjectOutputStream out) throws IOException { 53 | out.writeInt(hashCode); 54 | out.writeObject(asString); 55 | } 56 | 57 | private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { 58 | hashCode = in.readInt(); 59 | asString = (String) in.readObject(); 60 | el = Jsoup.parseBodyFragment(asString).body(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/engines/CombinedParserPickerFactoryTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.engines; 17 | 18 | import com.google.common.collect.Lists; 19 | 20 | import org.junit.*; 21 | 22 | import com.lastcalc.TokenList; 23 | import com.lastcalc.parsers.*; 24 | 25 | 26 | public class CombinedParserPickerFactoryTest { 27 | 28 | @Test 29 | public void test() { 30 | final Parser p1 = new RewriteParser(Lists.newArrayList("1", "1"), "one"); 31 | final Parser p2 = new RewriteParser(Lists.newArrayList("2", "2"), "two"); 32 | final Parser p3 = new RewriteParser(Lists.newArrayList("3", "3"), "three"); 33 | final Parser p4 = new RewriteParser(Lists.newArrayList("4", "4"), "four"); 34 | 35 | final FixedOrderParserPickerFactory f1 = new FixedOrderParserPickerFactory(p1, p2); 36 | final FixedOrderParserPickerFactory f2 = new FixedOrderParserPickerFactory(p3, p4); 37 | final CombinedParserPickerFactory f = new CombinedParserPickerFactory(f1, f2); 38 | 39 | final BacktrackingParseEngine pe = new BacktrackingParseEngine(f); 40 | 41 | final ParserContext context = new ParserContext(pe, Long.MAX_VALUE); 42 | final TokenList result = pe.parseAndGetLastStep(new TokenList.SimpleTokenList("1", "1", "2", "2", "3", "3", 43 | "4", "4"), 44 | context); 45 | 46 | Assert.assertEquals(TokenList.createD("one", "two", "three", "four"), result); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/bool/NotParser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.bool; 17 | 18 | import com.google.common.collect.Lists; 19 | 20 | import com.lastcalc.TokenList; 21 | import com.lastcalc.parsers.Parser; 22 | 23 | public class NotParser extends Parser { 24 | private static final long serialVersionUID = -7820633700412274072L; 25 | private static TokenList template = TokenList.createD(Boolean.class, Lists.newArrayList("and", "or", "xor"), 26 | Boolean.class); 27 | 28 | @Override 29 | public ParseResult parse(final TokenList tokens, final int templatePos) { 30 | final boolean a = (Boolean) tokens.get(templatePos); 31 | final boolean b = (Boolean) tokens.get(templatePos + 2); 32 | final String function = (String) tokens.get(templatePos + 1); 33 | boolean ret; 34 | if (function.equals("and")) { 35 | ret = a && b; 36 | } else if (function.equals("or")) { 37 | ret = a || b; 38 | } else { 39 | ret = a != b; 40 | } 41 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), ret)); 42 | } 43 | 44 | @Override 45 | public TokenList getTemplate() { 46 | return template; 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | return "BoolFunctionsParser".hashCode(); 52 | } 53 | 54 | @Override 55 | public boolean equals(final Object obj) { 56 | return obj instanceof NotParser; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/Misc.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc; 17 | 18 | import com.google.common.base.Joiner; 19 | import com.google.gson.Gson; 20 | import com.google.gson.GsonBuilder; 21 | 22 | import java.text.NumberFormat; 23 | import java.util.Random; 24 | 25 | public class Misc { 26 | public static Random rand = new Random(); 27 | 28 | private static final String randStrChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" 29 | + "0123456789"; 30 | 31 | public static String toString(final Iterable o) { 32 | final StringBuilder sb = new StringBuilder(); 33 | for (final Object io : o) { 34 | sb.append(io.getClass().getSimpleName() + " " + io + ", "); 35 | } 36 | return sb.toString(); 37 | } 38 | 39 | public static String randomString(final int digits) { 40 | final StringBuilder sb = new StringBuilder(digits); 41 | for (int x = 0; x < digits; x++) { 42 | sb.append(randStrChars.charAt(rand.nextInt(randStrChars.length()))); 43 | } 44 | return sb.toString(); 45 | } 46 | 47 | public static final Gson gson = new GsonBuilder().create(); 48 | 49 | public static NumberFormat numberFormat; 50 | static { 51 | numberFormat = NumberFormat.getInstance(); 52 | numberFormat.setGroupingUsed(false); 53 | numberFormat.setParseIntegerOnly(false); 54 | numberFormat.setMaximumFractionDigits(20); 55 | } 56 | 57 | public static final Joiner joiner = Joiner.on(' '); 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/collections/CollectionsTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.collections; 17 | 18 | import java.util.LinkedList; 19 | 20 | import junit.framework.Assert; 21 | 22 | import com.google.common.collect.Lists; 23 | 24 | import com.lastcalc.*; 25 | import com.lastcalc.engines.*; 26 | import com.lastcalc.parsers.*; 27 | 28 | 29 | public class CollectionsTest { 30 | 31 | // @Test 32 | public void getFromMapTest() { 33 | final PreParser bp = new PreParser(); 34 | final TokenList origTokens = Tokenizer.tokenize("get b from {a:A, b:B}"); 35 | final LinkedList parsers = Lists.newLinkedList(); 36 | com.lastcalc.parsers.Parser.getAll(parsers); 37 | final LinkedList priorityParsers = Lists.newLinkedList(); 38 | priorityParsers.add(new PreParser()); 39 | priorityParsers.add(new UserDefinedParserParser()); 40 | final FixedOrderParserPickerFactory priorityPPF = new FixedOrderParserPickerFactory(priorityParsers); 41 | final RecentFirstParserPickerFactory catchAllPPF = new RecentFirstParserPickerFactory(parsers); 42 | final ParseEngine st = new BacktrackingParseEngine(new CombinedParserPickerFactory(priorityPPF, catchAllPPF)); 43 | final ParserContext context = new ParserContext(st, Long.MAX_VALUE); 44 | final TokenList result = st.parseAndGetLastStep(origTokens, context); 45 | Assert.assertEquals(1, result.size()); 46 | Assert.assertEquals("B", result.get(0)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/cache/DocumentWrapper.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.cache; 17 | 18 | import java.io.*; 19 | 20 | import org.jsoup.Jsoup; 21 | import org.jsoup.nodes.Document; 22 | 23 | // Turns out Document has a crappy hashCode() implementation, 24 | // this makes it more efficient 25 | public class DocumentWrapper implements Serializable { 26 | private static final long serialVersionUID = -4508748891178262750L; 27 | 28 | public Document doc; 29 | 30 | String asString; 31 | 32 | private int hashCode; 33 | 34 | private String title; 35 | 36 | public DocumentWrapper(final Document doc) { 37 | this.doc = doc; 38 | asString = doc.toString(); 39 | hashCode = asString.hashCode(); 40 | title = doc.head().select("title").text(); 41 | 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return hashCode; 47 | } 48 | 49 | public String title() { 50 | return title; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return asString; 56 | } 57 | 58 | private void writeObject(final ObjectOutputStream out) throws IOException { 59 | out.writeInt(hashCode); 60 | out.writeObject(title); 61 | out.writeObject(asString); 62 | } 63 | 64 | private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { 65 | hashCode = in.readInt(); 66 | title = (String) in.readObject(); 67 | asString = (String) in.readObject(); 68 | doc = Jsoup.parse(asString); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/amounts/AmountParser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.amounts; 17 | 18 | import javax.measure.unit.Unit; 19 | 20 | import org.jscience.physics.amount.Amount; 21 | 22 | import com.lastcalc.TokenList; 23 | import com.lastcalc.parsers.Parser; 24 | 25 | 26 | public class AmountParser extends Parser { 27 | private static final long serialVersionUID = 9120544485351922021L; 28 | private static final TokenList template = TokenList.createD(Number.class, Unit.class); 29 | 30 | @Override 31 | public ParseResult parse(final TokenList tokens, final int templatePos) { 32 | final Number number = (Number) tokens.get(templatePos); 33 | final Unit unit = (Unit) tokens.get(templatePos + 1); 34 | if (number.longValue() == number.doubleValue()) 35 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), 36 | Amount.valueOf(number.longValue(), unit))); 37 | else 38 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), 39 | Amount.valueOf(number.doubleValue(), unit))); 40 | } 41 | 42 | @Override 43 | public TokenList getTemplate() { 44 | return template; 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return "AmountParser".hashCode(); 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return ""; 55 | } 56 | 57 | @Override 58 | public boolean equals(final Object obj) { 59 | return obj instanceof AmountParser; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/UDPApplier.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers; 17 | 18 | import com.lastcalc.TokenList; 19 | import com.lastcalc.parsers.UserDefinedParserParser.UserDefinedParser; 20 | 21 | public class UDPApplier extends Parser { 22 | private static final long serialVersionUID = -5412238263419670848L; 23 | private static TokenList template = TokenList.createD("apply", UserDefinedParser.class, "to"); 24 | 25 | @Override 26 | public TokenList getTemplate() { 27 | return template; 28 | } 29 | 30 | @Override 31 | public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) { 32 | final UserDefinedParser function = (UserDefinedParser) tokens.get(templatePos + 1); 33 | if (2 + templatePos + function.getTemplate().size() > tokens.size()) 34 | return ParseResult.fail(); 35 | final TokenList input = tokens.subList(templatePos + 3, templatePos + 3 + function.getTemplate().size()); 36 | if (function.matchTemplate(input) != 0) 37 | return ParseResult.fail(); 38 | final ParseResult parse = function.parse(input, 0, context); 39 | if (parse.isSuccess()) 40 | return ParseResult.success(tokens.replaceWithTokenList(templatePos, templatePos + 3 41 | + function.getTemplate().size(), parse.output)); 42 | else 43 | return ParseResult.fail(); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return "UDPApplier".hashCode(); 49 | } 50 | 51 | @Override 52 | public boolean equals(final Object obj) { 53 | return obj instanceof UDPApplier; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/strings/StringAppender.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.strings; 17 | 18 | import com.lastcalc.*; 19 | import com.lastcalc.Tokenizer.QuotedString; 20 | import com.lastcalc.parsers.Parser; 21 | 22 | public class StringAppender extends Parser { 23 | private static final long serialVersionUID = -7820633700412274072L; 24 | private static TokenList template = TokenList.createD(Object.class, "+", Object.class); 25 | 26 | @Override 27 | public ParseResult parse(final TokenList tokens, final int templatePos) { 28 | final Object o1 = tokens.get(templatePos); 29 | final Object o2 = tokens.get(templatePos + 2); 30 | QuotedString ret; 31 | if ((o1 instanceof QuotedString) && (o2 instanceof QuotedString)) { 32 | ret = new QuotedString(((QuotedString) o1).value + ((QuotedString) o2).value); 33 | } else if (o1 instanceof QuotedString) { 34 | ret = new QuotedString(((QuotedString) o1).value + o2.toString()); 35 | } else if (o2 instanceof QuotedString) { 36 | ret = new QuotedString(o1.toString() + ((QuotedString) o2).value); 37 | } else 38 | return ParseResult.fail(); 39 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), ret)); 40 | } 41 | 42 | @Override 43 | public TokenList getTemplate() { 44 | return template; 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return "StringAppender".hashCode(); 50 | } 51 | 52 | @Override 53 | public boolean equals(final Object obj) { 54 | return obj instanceof StringAppender; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/engines/FixedOrderParserPickerFactory.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.engines; 17 | 18 | import java.util.*; 19 | 20 | import com.google.common.collect.Lists; 21 | 22 | import com.lastcalc.parsers.*; 23 | 24 | 25 | public class FixedOrderParserPickerFactory extends ParserPickerFactory { 26 | private static final long serialVersionUID = -2346529366052255216L; 27 | private final LinkedList parsers; 28 | 29 | public FixedOrderParserPickerFactory(final Parser... parsers) { 30 | this.parsers = Lists.newLinkedList(Lists.newArrayList(parsers)); 31 | } 32 | 33 | public FixedOrderParserPickerFactory(final LinkedList parsers) { 34 | this.parsers = parsers; 35 | } 36 | 37 | @Override 38 | public void addParser(final Parser parser) { 39 | parsers.add(parser); 40 | } 41 | 42 | @Override 43 | public ParserPicker getPicker(final Map prevAttemptPos) { 44 | return new FixedOrderParserPicker(prevAttemptPos, parsers); 45 | } 46 | 47 | @Override 48 | public void teach(final Iterable step) { 49 | // Noop 50 | } 51 | 52 | public static class FixedOrderParserPicker extends ParserPicker { 53 | 54 | private final Iterable parsers; 55 | 56 | public FixedOrderParserPicker(final Map prevAttemptPos, final Iterable parsers) { 57 | super(prevAttemptPos); 58 | this.parsers = parsers; 59 | } 60 | 61 | @Override 62 | public ParseStep pickNext(final ParserContext context, final ParseStep previous) { 63 | final ParseStep next = getNext(context, parsers, previous); 64 | return next; 65 | } 66 | 67 | } 68 | 69 | public List getParsers() { 70 | return parsers; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/db/Line.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.db; 17 | 18 | import com.googlecode.objectify.annotation.Unindex; 19 | import com.lastcalc.TokenList; 20 | 21 | import java.io.IOException; 22 | import java.io.ObjectInputStream; 23 | import java.io.ObjectOutputStream; 24 | import java.io.Serializable; 25 | 26 | public class Line implements Serializable { 27 | private static final long serialVersionUID = 8234981855606438804L; 28 | 29 | public Line(final String question, final TokenList answer) 30 | throws IOException { 31 | this.question = question; 32 | this.answer = answer; 33 | } 34 | 35 | public Line(final int lineNum, final String question, final TokenList answer) 36 | throws IOException { 37 | this.lineNum=lineNum; 38 | this.question = question; 39 | this.answer = answer; 40 | } 41 | 42 | public int lineNum; 43 | 44 | @Unindex 45 | public String question; 46 | 47 | @Unindex 48 | public TokenList answer; 49 | 50 | // We serialize manually to ensure that TokenLists are serialized 51 | // efficiently 52 | private void writeObject(final ObjectOutputStream out) throws IOException { 53 | out.writeObject(question); 54 | out.writeInt(answer.size()); 55 | for (final Object o : answer) { 56 | out.writeObject(o); 57 | } 58 | } 59 | 60 | private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { 61 | question = (String) in.readObject(); 62 | final Object[] answer = new Object[in.readInt()]; 63 | for (int x = 0; x < answer.length; x++) { 64 | answer[x] = in.readObject(); 65 | } 66 | this.answer = TokenList.createD(answer); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/bool/IfThenElseParser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.bool; 17 | 18 | import com.lastcalc.TokenList; 19 | import com.lastcalc.parsers.Parser; 20 | import com.lastcalc.parsers.ParserContext; 21 | import com.lastcalc.parsers.PreParser; 22 | 23 | public class IfThenElseParser extends Parser { 24 | private static final long serialVersionUID = -7731508022221902181L; 25 | 26 | private static TokenList template = TokenList.createD("if", Boolean.class, "then"); 27 | 28 | @Override 29 | public TokenList getTemplate() { 30 | return template; 31 | } 32 | 33 | @Override 34 | public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) { 35 | final boolean condition = (Boolean) tokens.get(templatePos + 1); 36 | final int endPos = PreParser.findEdgeOrObjectForwards(tokens, templatePos + 2, null) + 1; 37 | final int elsePos = PreParser.findEdgeOrObjectForwards(tokens, templatePos + 2, "else"); 38 | TokenList ret; 39 | if (!tokens.get(elsePos).equals("else")) { 40 | if (condition) { 41 | ret = new TokenList.SubTokenList(tokens, templatePos + 3, endPos); 42 | } else { 43 | return ParseResult.fail(); 44 | } 45 | } else { 46 | if (condition) { 47 | ret = new TokenList.SubTokenList(tokens, templatePos + 3, elsePos); 48 | } else { 49 | ret = new TokenList.SubTokenList(tokens, elsePos + 1, endPos); 50 | } 51 | } 52 | return ParseResult.success(tokens.replaceWithTokenList(templatePos, endPos, ret)); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return "IfThenElseParser".hashCode(); 58 | } 59 | 60 | @Override 61 | public boolean equals(final Object obj) { 62 | return obj instanceof IfThenElseParser; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/servlets/WorksheetServletTest.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.servlets; 2 | 3 | 4 | import com.lastcalc.TokenList; 5 | import com.lastcalc.db.Worksheet; 6 | import org.jscience.mathematics.number.Number; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | 11 | import java.io.IOException; 12 | import java.util.HashMap; 13 | 14 | /******************************************************************************* 15 | * LastCalc - The last calculator you'll ever need 16 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 17 | * 18 | * This program is free software: you can redistribute it and/or modify it 19 | * under the terms of the GNU Affero General Public License as published 20 | * by the Free Software Foundation, either version 3 of the License, or 21 | * (at your option) any later version. 22 | * 23 | * This program is distributed in the hope that it will be useful, but 24 | * WITHOUT ANY WARRANTY; without even the implied warranty of 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | * PURPOSE. See the GNU Affero General Public License for more 27 | * details. 28 | ******************************************************************************/ 29 | public class WorksheetServletTest { 30 | 31 | 32 | @Test 33 | public void testFunctionCreation() throws IOException { 34 | 35 | final Worksheet worksheet=new Worksheet(); 36 | 37 | { 38 | WorksheetServlet.WorksheetRequest worksheetRequest=new WorksheetServlet.WorksheetRequest(); 39 | 40 | worksheetRequest.questions=new HashMap(); 41 | worksheetRequest.questions.put(1,"double X = X*2"); 42 | 43 | 44 | WorksheetServlet.getWorksheetResponse(worksheet, worksheetRequest, ""); 45 | 46 | } 47 | 48 | { 49 | WorksheetServlet.WorksheetRequest worksheetRequest=new WorksheetServlet.WorksheetRequest(); 50 | 51 | worksheetRequest.questions=new HashMap(); 52 | worksheetRequest.questions.put(2,"double 5"); 53 | WorksheetServlet.getWorksheetResponse(worksheet, worksheetRequest, ""); 54 | } 55 | 56 | 57 | final TokenList result=worksheet.qaPairs.get(1).answer; 58 | 59 | 60 | Assert.assertEquals(1, result.size()); 61 | 62 | Assert.assertTrue("Assert that " + result.get(0).getClass() + " is a Number", result.get(0) instanceof org.jscience.mathematics.number.Number); 63 | double value = ((Number) result.get(0)).doubleValue(); 64 | Assert.assertEquals(10.0, value,0.01); 65 | 66 | System.out.println("worksheet servlet test finished"); 67 | 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/collections/FoldLeft.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.collections; 17 | 18 | import java.util.List; 19 | 20 | import com.lastcalc.TokenList; 21 | import com.lastcalc.parsers.*; 22 | import com.lastcalc.parsers.UserDefinedParserParser.UserDefinedParser; 23 | 24 | public class FoldLeft extends Parser { 25 | private static final long serialVersionUID = 9178891850811247754L; 26 | private static TokenList template = TokenList.createD("fold", UserDefinedParser.class, "over", List.class, "with", 27 | Object.class); 28 | 29 | @Override 30 | public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) { 31 | Object ret = tokens.get(templatePos + 5); 32 | final UserDefinedParser udp = (UserDefinedParser) tokens.get(templatePos + 1); 33 | final Object datastructure = tokens.get(templatePos + 3); 34 | if (datastructure instanceof List) { 35 | if (udp.getTemplate().size() != 2) 36 | return ParseResult.fail(); 37 | final List list = (List) datastructure; 38 | for (final Object o : list) { 39 | TokenList r = udp.parse(TokenList.createD(ret, o), 0).output; 40 | r = context.parseEngine.parseAndGetLastStep(r, context); 41 | if (r.size() != 1) 42 | return ParseResult.fail(); 43 | else { 44 | ret = r.get(0); 45 | } 46 | } 47 | } else 48 | return ParseResult.fail(); 49 | return ParseResult.success(tokens.replaceWithTokenList(templatePos, templatePos + template.size(), 50 | TokenList.createD(ret))); 51 | } 52 | 53 | @Override 54 | public TokenList getTemplate() { 55 | return template; 56 | } 57 | 58 | @Override 59 | public int hashCode() { 60 | return "FoldLeft".hashCode(); 61 | } 62 | 63 | @Override 64 | public boolean equals(final Object obj) { 65 | return obj instanceof FoldLeft; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/math/RadixConverter.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.math; 17 | 18 | import com.google.common.collect.Lists; 19 | 20 | import org.jscience.mathematics.number.LargeInteger; 21 | 22 | import com.lastcalc.TokenList; 23 | import com.lastcalc.parsers.Parser; 24 | 25 | 26 | public class RadixConverter extends Parser { 27 | private static final long serialVersionUID = 9120544485351922021L; 28 | private static final TokenList template = TokenList.createD(Lists.newArrayList(LargeInteger.class, Radix.class), 29 | Lists.newArrayList("to", "as", "in"), 30 | Lists.newArrayList("bin", "binary", "hex", "hexadecimal", "oct", "octal", "dec", "decimal")); 31 | 32 | @Override 33 | public ParseResult parse(final TokenList tokens, final int templatePos) { 34 | final Object num = tokens.get(templatePos); 35 | final long li = num instanceof LargeInteger ?((LargeInteger) tokens.get(templatePos)).longValue(): ((Radix) num).integer; 36 | 37 | final String convertTo = (String) tokens.get(templatePos + 2); 38 | Object result; 39 | if (convertTo.startsWith("bin")) { 40 | result = new Radix(li, 2); 41 | } else if (convertTo.startsWith("hex")) { 42 | result = new Radix(li, 16); 43 | } else if (convertTo.startsWith("oct")) { 44 | result = new Radix(li, 8); 45 | } else { 46 | result = LargeInteger.valueOf(li); 47 | } 48 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), result)); 49 | } 50 | 51 | @Override 52 | public TokenList getTemplate() { 53 | return template; 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | return "RadixConverter".hashCode(); 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return ""; 64 | } 65 | 66 | @Override 67 | public boolean equals(final Object obj) { 68 | return obj instanceof RadixConverter; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/math/GCDLCMTest.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.math; 2 | 3 | import com.lastcalc.TokenList; 4 | import com.lastcalc.parsers.Parser; 5 | import junit.framework.Assert; 6 | import org.jscience.mathematics.number.LargeInteger; 7 | import org.junit.Test; 8 | 9 | /** 10 | * **************************************************************************** 11 | * LastCalc - The last calculator you'll ever need 12 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 13 | *

14 | * This program is free software: you can redistribute it and/or modify it 15 | * under the terms of the GNU Affero General Public License as published 16 | * by the Free Software Foundation, either version 3 of the License, or 17 | * (at your option) any later version. 18 | *

19 | * This program is distributed in the hope that it will be useful, but 20 | * WITHOUT ANY WARRANTY; without even the implied warranty of 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 22 | * PURPOSE. See the GNU Affero General Public License for more 23 | * details. 24 | * **************************************************************************** 25 | */ 26 | public class GCDLCMTest { 27 | 28 | 29 | @Test 30 | public void gcdlcmTest(){ 31 | 32 | final GCDLCMParser gcdParser = new GCDLCMParser(); 33 | Parser.ParseResult pr=gcdParser.parse(TokenList.createD("blah", "gcd", LargeInteger.valueOf(3), LargeInteger.valueOf(4), "blah"),1); 34 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 35 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", 1,"blah"), pr.output); 36 | 37 | pr=gcdParser.parse(TokenList.createD("blah", "gcd", LargeInteger.valueOf(100), LargeInteger.valueOf(90), "blah"),1); 38 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 39 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", 10,"blah"), pr.output); 40 | 41 | pr=gcdParser.parse(TokenList.createD("blah", "lcm", LargeInteger.valueOf(3), LargeInteger.valueOf(4), "blah"),1); 42 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 43 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", 12,"blah"), pr.output); 44 | 45 | pr=gcdParser.parse(TokenList.createD("blah", "lcm", LargeInteger.valueOf(100), LargeInteger.valueOf(90), "blah"),1); 46 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 47 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", 900,"blah"), pr.output); 48 | 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/web/GetFromElement.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.web; 17 | 18 | import java.util.Map; 19 | 20 | import com.google.common.collect.*; 21 | 22 | import org.jsoup.nodes.Attribute; 23 | 24 | import com.lastcalc.*; 25 | import com.lastcalc.cache.ElementWrapper; 26 | import com.lastcalc.parsers.Parser; 27 | 28 | 29 | public class GetFromElement extends Parser { 30 | 31 | private static TokenList template = TokenList.createD("get", Lists.newArrayList("text", "attributes", "tag"), 32 | "from", ElementWrapper.class); 33 | 34 | /** 35 | * 36 | */ 37 | private static final long serialVersionUID = 5755928813441453688L; 38 | 39 | @Override 40 | public ParseResult parse(final TokenList tokens, final int templatePos) { 41 | final String what = (String) tokens.get(templatePos + 1); 42 | final ElementWrapper ew = (ElementWrapper) tokens.get(templatePos + 3); 43 | Object ret; 44 | if (what.equals("text")) { 45 | ret = new Tokenizer.QuotedString(ew.el.text()); 46 | } else if (what.equals("attributes")) { 47 | final Map attributes = Maps.newLinkedHashMap(); 48 | for (final Attribute x : ew.el.attributes()) { 49 | // TODO: Verify that these are single values when tokenized 50 | attributes.put(new Tokenizer.QuotedString(x.getKey()), new Tokenizer.QuotedString(x.getValue())); 51 | } 52 | ret = TokenList.createD(attributes); 53 | } else if (what.equals("tag")) { 54 | ret = TokenList.createD(ew.el.tagName()); 55 | } else 56 | return ParseResult.fail(); 57 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), ret)); 58 | } 59 | 60 | @Override 61 | public TokenList getTemplate() { 62 | return template; 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return "GetFromElement".hashCode(); 68 | } 69 | 70 | @Override 71 | public boolean equals(final Object obj) { 72 | return obj instanceof GetFromElement; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/RewriteParser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers; 17 | 18 | import java.util.ArrayList; 19 | 20 | import com.lastcalc.TokenList; 21 | 22 | 23 | public class RewriteParser extends Parser { 24 | 25 | private static final long serialVersionUID = 7536991519287899564L; 26 | private final TokenList template; 27 | private final TokenList to; 28 | 29 | public RewriteParser(final Object from, final Object to) { 30 | if (from instanceof ArrayList) { 31 | template = TokenList.create((ArrayList) from); 32 | } else { 33 | template = TokenList.createD(from); 34 | } 35 | if (to instanceof ArrayList) { 36 | this.to = TokenList.create((ArrayList) to); 37 | } else { 38 | this.to = TokenList.createD(to); 39 | } 40 | } 41 | 42 | @Override 43 | public TokenList getTemplate() { 44 | return template; 45 | } 46 | 47 | @Override 48 | public ParseResult parse(final TokenList tokens, final int templatePos) { 49 | return ParseResult.success(tokens.replaceWithTokenList(templatePos, templatePos + template.size(), to)); 50 | } 51 | 52 | @Override 53 | public int hashCode() { 54 | final int prime = 31; 55 | int result = 1; 56 | result = prime * result + ((template == null) ? 0 : template.hashCode()); 57 | result = prime * result + ((to == null) ? 0 : to.hashCode()); 58 | return result; 59 | } 60 | 61 | @Override 62 | public boolean equals(final Object obj) { 63 | if (this == obj) 64 | return true; 65 | if (obj == null) 66 | return false; 67 | if (!(obj instanceof RewriteParser)) 68 | return false; 69 | final RewriteParser other = (RewriteParser) obj; 70 | if (template == null) { 71 | if (other.template != null) 72 | return false; 73 | } else if (!template.equals(other.template)) 74 | return false; 75 | if (to == null) { 76 | if (other.to != null) 77 | return false; 78 | } else if (!to.equals(other.to)) 79 | return false; 80 | return true; 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/collections/ApplyTo.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.collections; 17 | 18 | import java.util.*; 19 | 20 | import com.google.common.collect.*; 21 | 22 | import com.lastcalc.TokenList; 23 | import com.lastcalc.parsers.*; 24 | import com.lastcalc.parsers.UserDefinedParserParser.UserDefinedParser; 25 | 26 | public class ApplyTo extends Parser { 27 | private static final long serialVersionUID = 9178891850811247754L; 28 | private static TokenList template = TokenList.createD("apply", UserDefinedParser.class, "to", 29 | Lists.newArrayList(List.class, Map.class)); 30 | 31 | @Override 32 | public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) { 33 | final UserDefinedParser udp = (UserDefinedParser) tokens.get(templatePos + 1); 34 | final Object datastructure = tokens.get(templatePos + 3); 35 | List ret; 36 | if (datastructure instanceof List) { 37 | if (udp.variables.size() != 1 || udp.getTemplate().size() != 1) 38 | return ParseResult.fail(); 39 | final List list = (List) datastructure; 40 | ret = Lists.newArrayListWithCapacity(list.size() * 4); 41 | ret.add("["); 42 | for (final Object o : list) { 43 | final TokenList r = context.parseEngine.parseAndGetLastStep(udp.parse(TokenList.createD(o), 0).output, 44 | context); 45 | Iterables.addAll(ret, r); 46 | ret.add(","); 47 | } 48 | ret.set(ret.size() - 1, "]"); // Overwrite last comma 49 | } else 50 | return ParseResult.fail(); 51 | return ParseResult.success(tokens.replaceWithTokenList(templatePos, templatePos + template.size(), 52 | TokenList.create(ret))); 53 | } 54 | 55 | @Override 56 | public TokenList getTemplate() { 57 | return template; 58 | } 59 | 60 | @Override 61 | public int hashCode() { 62 | return "ApplyToList".hashCode(); 63 | } 64 | 65 | @Override 66 | public boolean equals(final Object obj) { 67 | return obj instanceof ApplyTo; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/amounts/AmountConverterParser.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.amounts; 17 | 18 | import javax.measure.converter.ConversionException; 19 | import javax.measure.unit.Unit; 20 | 21 | import com.google.common.collect.Lists; 22 | 23 | import org.jscience.mathematics.number.FloatingPoint; 24 | import org.jscience.physics.amount.Amount; 25 | 26 | import com.lastcalc.TokenList; 27 | import com.lastcalc.parsers.Parser; 28 | 29 | 30 | public class AmountConverterParser extends Parser { 31 | private static final long serialVersionUID = -2549484003198615095L; 32 | private static final TokenList template = TokenList.createD(Amount.class, 33 | Lists.newArrayList("in", "to", "as"), 34 | Object.class); 35 | 36 | @Override 37 | public TokenList getTemplate() { 38 | return template; 39 | } 40 | 41 | @Override 42 | public ParseResult parse(final TokenList tokens, final int templatePos) { 43 | final Amount amount = (Amount) tokens.get(templatePos); 44 | if (tokens.get(templatePos + 2) instanceof Unit) { 45 | final Unit unit = (Unit) tokens.get(templatePos + 2); 46 | try { 47 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), 48 | amount.to(unit))); 49 | } catch (final ConversionException e) { 50 | // return ParseResult.error("Cannot convert " + amount.getUnit() + 51 | // " to " + unit); 52 | return ParseResult.fail(); 53 | } 54 | } else if (tokens.get(templatePos + 2).equals("number")) 55 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), 56 | FloatingPoint.valueOf(amount.getEstimatedValue()))); 57 | else 58 | return ParseResult.fail(); 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return ""; 64 | } 65 | 66 | @Override 67 | public int hashCode() { 68 | return "AmountConverterParser".hashCode(); 69 | } 70 | 71 | @Override 72 | public boolean equals(final Object obj) { 73 | return obj instanceof AmountConverterParser; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/engines/CombinedParserPickerFactory.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.engines; 17 | 18 | import java.util.*; 19 | 20 | import com.google.common.collect.*; 21 | 22 | import com.lastcalc.parsers.*; 23 | 24 | 25 | public class CombinedParserPickerFactory extends ParserPickerFactory { 26 | private static final long serialVersionUID = -9047872184877535738L; 27 | private final Iterable factories; 28 | 29 | public CombinedParserPickerFactory(final ParserPickerFactory... factories) { 30 | this(Lists.newArrayList(factories)); 31 | } 32 | 33 | public CombinedParserPickerFactory(final Iterable factories) { 34 | this.factories = factories; 35 | } 36 | 37 | @Override 38 | public ParserPicker getPicker(final Map prevAttemptPos) { 39 | return new CombinedParserPicker(prevAttemptPos, factories); 40 | } 41 | 42 | @Override 43 | public void teach(final Iterable step) { 44 | for (final ParserPickerFactory ppf : factories) { 45 | ppf.teach(step); 46 | } 47 | } 48 | 49 | public static class CombinedParserPicker extends ParserPicker { 50 | private final Iterable ppfs; 51 | 52 | public CombinedParserPicker(final Map prevAttemptPos, final Iterable ppfs) { 53 | super(prevAttemptPos); 54 | this.ppfs = ppfs; 55 | } 56 | 57 | @Override 58 | public ParseStep pickNext(final ParserContext context, final ParseStep previous) { 59 | for (final ParserPickerFactory ppf : ppfs) { 60 | final ParseStep ps = ppf.getPicker(prevAttemptPos).pickNext(context, previous); 61 | if (ps != null) 62 | return ps; 63 | } 64 | return null; 65 | } 66 | 67 | } 68 | 69 | @Override 70 | public Collection getParsers() { 71 | final Set parsers = Sets.newHashSet(); 72 | for (final ParserPickerFactory ppf : factories) { 73 | parsers.addAll(ppf.getParsers()); 74 | } 75 | return parsers; 76 | } 77 | 78 | @Override 79 | public void addParser(final Parser parser) { 80 | throw new UnsupportedOperationException(); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/math/GCDLCMParser.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.math; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.lastcalc.TokenList; 5 | import com.lastcalc.parsers.Parser; 6 | import org.jscience.mathematics.number.LargeInteger; 7 | 8 | /** 9 | * **************************************************************************** 10 | * LastCalc - The last calculator you'll ever need 11 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 12 | *

13 | * This program is free software: you can redistribute it and/or modify it 14 | * under the terms of the GNU Affero General Public License as published 15 | * by the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | *

18 | * This program is distributed in the hope that it will be useful, but 19 | * WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 21 | * PURPOSE. See the GNU Affero General Public License for more 22 | * details. 23 | * **************************************************************************** 24 | */ 25 | public class GCDLCMParser extends Parser{ 26 | 27 | 28 | private static TokenList template = TokenList.createD(Lists. newArrayList("gcd", "lcm"),Number.class, Number.class); 29 | 30 | @Override 31 | public TokenList getTemplate() { 32 | return template; 33 | } 34 | 35 | 36 | @Override 37 | public Parser.ParseResult parse(final TokenList tokens, final int templatePos) { 38 | 39 | final String op = (String) tokens.get(templatePos); 40 | final Integer input1 = ((LargeInteger)tokens.get(templatePos + 1)).intValue(); 41 | final Integer input2 = ((LargeInteger)tokens.get(templatePos + 2)).intValue(); 42 | 43 | 44 | if(op.equals("gcd")){ 45 | 46 | Integer result=gcd_iter(input1,input2); 47 | 48 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), result)); 49 | } 50 | else if(op.equals("lcm")){ 51 | 52 | Integer result=lcm(input1,input2); 53 | 54 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), result)); 55 | } 56 | else{ 57 | return Parser.ParseResult.fail(); 58 | } 59 | } 60 | 61 | private Integer gcd_iter(Integer u, Integer v) { 62 | Integer t; 63 | while (v!=0) { 64 | t = u; 65 | u = v; 66 | v = t % v; 67 | } 68 | return u < 0 ? -u : u; /* abs(u) */ 69 | } 70 | 71 | private Integer lcm(Integer a, Integer b) 72 | { 73 | return a * (b / gcd_iter(a, b)); 74 | } 75 | 76 | @Override 77 | public int hashCode() { 78 | return 0; 79 | } 80 | 81 | @Override 82 | public boolean equals(Object obj) { 83 | return false; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/collections/Filter.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.collections; 17 | 18 | import java.util.List; 19 | 20 | import com.google.common.collect.Lists; 21 | 22 | import com.lastcalc.TokenList; 23 | import com.lastcalc.parsers.*; 24 | import com.lastcalc.parsers.UserDefinedParserParser.UserDefinedParser; 25 | 26 | public class Filter extends Parser { 27 | private static final long serialVersionUID = 9178891850811247754L; 28 | private static TokenList template = TokenList.createD("filter", Lists.newArrayList(List.class), "with", 29 | UserDefinedParser.class); 30 | 31 | @Override 32 | public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) { 33 | final UserDefinedParser udp = (UserDefinedParser) tokens.get(templatePos + 3); 34 | final Object datastructure = tokens.get(templatePos + 1); 35 | List ret; 36 | if (datastructure instanceof List) { 37 | if (udp.variables.size() != 1 || udp.getTemplate().size() != 1) 38 | return ParseResult.fail(); 39 | final List list = (List) datastructure; 40 | ret = Lists.newArrayListWithCapacity(list.size() * 4); 41 | ret.add("["); 42 | for (final Object o : list) { 43 | final TokenList result = context.parseEngine.parseAndGetLastStep( 44 | udp.parse(TokenList.createD(o), 0).output, context); 45 | if (result.size() != 1 || !(result.get(0) instanceof Boolean)) 46 | return ParseResult.fail(); 47 | if (result.get(0).equals(true)) { 48 | ret.add(o); 49 | ret.add(","); 50 | } 51 | } 52 | ret.set(ret.size() - 1, "]"); // Overwrite last comma 53 | } else 54 | return ParseResult.fail(); 55 | return ParseResult.success(tokens.replaceWithTokenList(templatePos, templatePos + template.size(), 56 | TokenList.create(ret))); 57 | } 58 | 59 | @Override 60 | public TokenList getTemplate() { 61 | return template; 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return "Filter".hashCode(); 67 | } 68 | 69 | @Override 70 | public boolean equals(final Object obj) { 71 | return obj instanceof Filter; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/collections/GetFromListOrMap.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.collections; 17 | 18 | import java.util.*; 19 | 20 | import com.google.common.collect.Lists; 21 | 22 | import org.jscience.mathematics.number.LargeInteger; 23 | 24 | import com.lastcalc.TokenList; 25 | import com.lastcalc.parsers.Parser; 26 | 27 | 28 | public class GetFromListOrMap extends Parser { 29 | 30 | private static TokenList template = TokenList.createD("get", Object.class, "from", 31 | Lists.newArrayList(Map.class, List.class)); 32 | 33 | /** 34 | * 35 | */ 36 | private static final long serialVersionUID = 5755928813441453688L; 37 | 38 | @Override 39 | public ParseResult parse(final TokenList tokens, final int templatePos) { 40 | final Object toGet = tokens.get(templatePos + 1); 41 | if (tokens.get(templatePos + 3) instanceof Map) { 42 | final Map map = (Map) tokens.get(templatePos + 3); 43 | final Object got = map.get(toGet); 44 | if (got != null) 45 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), got)); 46 | else 47 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), false)); 48 | } else if (tokens.get(templatePos + 3) instanceof List) { 49 | final List list = (List) tokens.get(templatePos + 3); 50 | if (toGet instanceof LargeInteger) { 51 | final int ix = ((LargeInteger) toGet).intValue(); 52 | if (ix < 0 || ix >= list.size()) 53 | return ParseResult.fail(); 54 | else 55 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), 56 | list.get(ix))); 57 | } else 58 | return ParseResult.fail(); 59 | } else 60 | return ParseResult.fail(); 61 | } 62 | 63 | @Override 64 | public TokenList getTemplate() { 65 | return template; 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | return "GetFromListOrMap".hashCode(); 71 | } 72 | 73 | @Override 74 | public boolean equals(final Object obj) { 75 | return obj instanceof GetFromListOrMap; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/web/HttpRetriever.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.web; 17 | 18 | import java.io.IOException; 19 | import java.net.*; 20 | 21 | import org.jsoup.Jsoup; 22 | 23 | import com.lastcalc.*; 24 | import com.lastcalc.Tokenizer.QuotedString; 25 | import com.lastcalc.cache.*; 26 | import com.lastcalc.parsers.*; 27 | 28 | public class HttpRetriever extends Parser { 29 | private static final long serialVersionUID = 429169446256736079L; 30 | private static TokenList template = TokenList.createD("retrieve", QuotedString.class); 31 | 32 | @Override 33 | public TokenList getTemplate() { 34 | return template; 35 | } 36 | 37 | @Override 38 | public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) { 39 | URL url; 40 | try { 41 | url = new URL(((QuotedString) tokens.get(templatePos + 1)).value); 42 | } catch (final MalformedURLException e) { 43 | return ParseResult.fail(); 44 | } 45 | 46 | final Object cached = ObjectCache.getSlow(1000l * 60l * 60l * 24l, url); 47 | 48 | if (cached != null) 49 | return ParseResult 50 | .success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), cached)); 51 | 52 | URLConnection connection; 53 | try { 54 | connection = url.openConnection(); 55 | } catch (final IOException e) { 56 | return ParseResult.fail(); 57 | } 58 | final String contentType = connection.getContentType(); 59 | if (contentType.toLowerCase().contains("text/html")) { 60 | DocumentWrapper doc; 61 | try { 62 | doc = new DocumentWrapper(Jsoup.parse(connection.getInputStream(), "UTF-8", "/")); 63 | } catch (final IOException e) { 64 | return ParseResult.fail(); 65 | } 66 | ObjectCache.put(1000l * 60l * 60l * 24l, doc, url); 67 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), doc)); 68 | } 69 | return ParseResult.fail(); 70 | 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | return "HttpRetriever".hashCode(); 76 | } 77 | 78 | @Override 79 | public boolean equals(final Object obj) { 80 | return obj instanceof HttpRetriever; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/webapp/js/rangy-selectionsaverestore.js: -------------------------------------------------------------------------------- 1 | /* 2 | Selection save and restore module for Rangy. 3 | Saves and restores user selections using marker invisible elements in the DOM. 4 | 5 | Part of Rangy, a cross-browser JavaScript range and selection library 6 | http://code.google.com/p/rangy/ 7 | 8 | Depends on Rangy core. 9 | 10 | Copyright 2011, Tim Down 11 | Licensed under the MIT license. 12 | Version: 1.2.2 13 | Build date: 13 November 2011 14 | */ 15 | rangy.createModule("SaveRestore",function(h,m){function n(a,g){var e="selectionBoundary_"+ +new Date+"_"+(""+Math.random()).slice(2),c,f=p.getDocument(a.startContainer),d=a.cloneRange();d.collapse(g);c=f.createElement("span");c.id=e;c.style.lineHeight="0";c.style.display="none";c.className="rangySelectionBoundary";c.appendChild(f.createTextNode(q));d.insertNode(c);d.detach();return c}function o(a,g,e,c){if(a=(a||document).getElementById(e)){g[c?"setStartBefore":"setEndBefore"](a);a.parentNode.removeChild(a)}else m.warn("Marker element has been removed. Cannot restore selection.")} 16 | function r(a,g){return g.compareBoundaryPoints(a.START_TO_START,a)}function k(a,g){var e=(a||document).getElementById(g);e&&e.parentNode.removeChild(e)}h.requireModules(["DomUtil","DomRange","WrappedRange"]);var p=h.dom,q="\ufeff";h.saveSelection=function(a){a=a||window;var g=a.document;if(h.isSelectionValid(a)){var e=h.getSelection(a),c=e.getAllRanges(),f=[],d,j;c.sort(r);for(var b=0,i=c.length;b=0;--b){d=c[b];if(d.collapsed)d.collapseBefore((g||document).getElementById(f[b].markerId));else{d.setEndBefore((g||document).getElementById(f[b].endMarkerId));d.setStartAfter((g||document).getElementById(f[b].startMarkerId))}}e.setRanges(c);return{win:a,doc:g,rangeInfos:f,restored:false}}else m.warn("Cannot save selection. This usually happens when the selection is collapsed and the selection document has lost focus.")}; 18 | h.restoreSelection=function(a,g){if(!a.restored){for(var e=a.rangeInfos,c=h.getSelection(a.win),f=[],d=e.length,j=d-1,b,i;j>=0;--j){b=e[j];i=h.createRange(a.doc);if(b.collapsed)if(b=(a.doc||document).getElementById(b.markerId)){b.style.display="inline";var l=b.previousSibling;if(l&&l.nodeType==3){b.parentNode.removeChild(b);i.collapseToPoint(l,l.length)}else{i.collapseBefore(b);b.parentNode.removeChild(b)}}else m.warn("Marker element has been removed. Cannot restore selection.");else{o(a.doc,i,b.startMarkerId, 19 | true);o(a.doc,i,b.endMarkerId,false)}d==1&&i.normalizeBoundaries();f[j]=i}if(d==1&&g&&h.features.selectionHasExtend&&e[0].backwards){c.removeAllRanges();c.addRange(f[0],true)}else c.setRanges(f);a.restored=true}};h.removeMarkerElement=k;h.removeMarkers=function(a){for(var g=a.rangeInfos,e=0,c=g.length,f;e newArrayList("factorial"),LargeInteger.class); 38 | 39 | //private static TokenList template=TokenList.createD(LargeInteger.class,Lists. newArrayList("!")); 40 | 41 | @Override 42 | public TokenList getTemplate() { 43 | return template; 44 | } 45 | 46 | @SuppressWarnings("rawtypes") 47 | @Override 48 | public ParseResult parse(final TokenList tokens, final int templatePos) { 49 | 50 | final String op = (String) tokens.get(templatePos); 51 | final LargeInteger input = (LargeInteger) tokens.get(templatePos + 1); 52 | Number result = null; 53 | 54 | if(op.equals("factorial")){ 55 | //System.out.println("INput is: "+input); 56 | 57 | if(input.isLessThan(LargeInteger.valueOf(20)) && input.isGreaterThan(LargeInteger.ZERO)){ 58 | result = LargeInteger.valueOf(factorial(input.longValue())); 59 | 60 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos+template.size(), result)); 61 | } 62 | 63 | 64 | } 65 | return ParseResult.fail(); 66 | } 67 | 68 | protected long factorial(long input){ 69 | long fact = 1; 70 | for (long x = input; x > 1; x--){ 71 | fact *= x; 72 | } 73 | return fact; 74 | } 75 | 76 | @Override 77 | public String toString() { 78 | return ""; 79 | } 80 | 81 | @Override 82 | public int hashCode() { 83 | return "FactorialParser".hashCode(); 84 | } 85 | 86 | @Override 87 | public boolean equals(final Object obj) { 88 | return false; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/web/Select.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.web; 17 | 18 | import java.util.List; 19 | 20 | import com.google.common.collect.Lists; 21 | 22 | import org.jsoup.nodes.Element; 23 | import org.jsoup.select.Elements; 24 | 25 | import com.lastcalc.*; 26 | import com.lastcalc.Tokenizer.QuotedString; 27 | import com.lastcalc.cache.*; 28 | import com.lastcalc.parsers.*; 29 | 30 | public class Select extends Parser { 31 | 32 | private static final TokenList template = TokenList.createD("select", QuotedString.class, "from", 33 | Lists. newArrayList(DocumentWrapper.class, ElementWrapper.class)); 34 | 35 | @Override 36 | public TokenList getTemplate() { 37 | return template; 38 | } 39 | 40 | @Override 41 | public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) { 42 | final String selectStatement = ((QuotedString) tokens.get(templatePos + 1)).value; 43 | final Object docOrElement = tokens.get(templatePos + 3); 44 | final Object cached = ObjectCache.getFast(Long.MAX_VALUE, "select", selectStatement, docOrElement); 45 | if (cached != null) 46 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos+template.size(), cached)); 47 | Element el; 48 | if (docOrElement instanceof DocumentWrapper) { 49 | el = ((DocumentWrapper) docOrElement).doc; 50 | } else { 51 | el = ((ElementWrapper) docOrElement).el; 52 | } 53 | final Elements elements = el.select(selectStatement); 54 | 55 | if (elements.size() == 1) 56 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos+template.size(), new ElementWrapper(elements.first()))); 57 | else { 58 | final List elementList = Lists.newArrayListWithCapacity(elements.size()); 59 | for (final Element e : elements) { 60 | elementList.add(new ElementWrapper(e)); 61 | } 62 | return ParseResult 63 | .success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), elementList)); 64 | } 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return "Select".hashCode(); 70 | } 71 | 72 | @Override 73 | public boolean equals(final Object obj) { 74 | return obj instanceof Select; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/engines/RecentFirstParserPickerFactory.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.engines; 17 | 18 | import java.util.*; 19 | import java.util.concurrent.locks.ReentrantReadWriteLock; 20 | 21 | import com.google.common.collect.*; 22 | 23 | import com.lastcalc.parsers.*; 24 | 25 | 26 | public class RecentFirstParserPickerFactory extends ParserPickerFactory { 27 | 28 | ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); 29 | 30 | private static final long serialVersionUID = -5521465155099741906L; 31 | 32 | LinkedList parsers = new LinkedList(); 33 | 34 | private final int maxParsers; 35 | 36 | public RecentFirstParserPickerFactory(final Iterable parsers) { 37 | this(parsers, Integer.MAX_VALUE); 38 | } 39 | 40 | public RecentFirstParserPickerFactory(final Iterable parsers, final int maxParsers) { 41 | this.maxParsers = maxParsers; 42 | Iterables.addAll(this.parsers, parsers); 43 | while (this.parsers.size() > maxParsers) { 44 | this.parsers.removeLast(); 45 | } 46 | } 47 | 48 | @Override 49 | public void addParser(final Parser parser) { 50 | parsers.add(parser); 51 | } 52 | 53 | @Override 54 | public void teach(final Iterable steps) { 55 | final ArrayList reversed = Lists.newArrayList(steps); 56 | Collections.reverse(reversed); 57 | rwl.writeLock().lock(); 58 | for (final ParseStep ps : reversed) { 59 | // TODO: This is slow, probably need to use a better 60 | // datastructure for parsers, perhaps LinkedHashMap 61 | // or something 62 | parsers.remove(ps.parser); 63 | parsers.addFirst(ps.parser); 64 | } 65 | while (parsers.size() > maxParsers) { 66 | parsers.removeLast(); 67 | } 68 | rwl.writeLock().unlock(); 69 | } 70 | 71 | 72 | @Override 73 | public ParserPicker getPicker(final Map prevAttemptPos) { 74 | return new ParserPicker(prevAttemptPos) { 75 | 76 | @Override 77 | public ParseStep pickNext(final ParserContext context, final ParseStep previous) { 78 | // matchTemplate 79 | rwl.readLock().lock(); 80 | final ParseStep nextParseStep = getNext(context, parsers, previous); 81 | rwl.readLock().unlock(); 82 | return nextParseStep; 83 | } 84 | }; 85 | } 86 | 87 | @Override 88 | public List getParsers() { 89 | return parsers; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/math/IsPrimeTest.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.math; 2 | 3 | import com.lastcalc.TokenList; 4 | import com.lastcalc.parsers.Parser; 5 | import junit.framework.Assert; 6 | import org.jscience.mathematics.number.LargeInteger; 7 | import org.junit.Test; 8 | 9 | import java.util.ArrayList; 10 | 11 | /** 12 | * **************************************************************************** 13 | * LastCalc - The last calculator you'll ever need 14 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 15 | *

16 | * This program is free software: you can redistribute it and/or modify it 17 | * under the terms of the GNU Affero General Public License as published 18 | * by the Free Software Foundation, either version 3 of the License, or 19 | * (at your option) any later version. 20 | *

21 | * This program is distributed in the hope that it will be useful, but 22 | * WITHOUT ANY WARRANTY; without even the implied warranty of 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 24 | * PURPOSE. See the GNU Affero General Public License for more 25 | * details. 26 | * **************************************************************************** 27 | */ 28 | public class IsPrimeTest { 29 | 30 | 31 | 32 | @Test 33 | public void isPrimeTest(){ 34 | 35 | final IsPrimeParser ist = new IsPrimeParser(); 36 | Parser.ParseResult pr=ist.parse(TokenList.createD("blah", "isprime", LargeInteger.valueOf(3), "blah"),1); 37 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 38 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", true,"blah"), pr.output); 39 | 40 | pr=ist.parse(TokenList.createD("blah", "isprime", LargeInteger.valueOf(5), "blah"),1); 41 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 42 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", true,"blah"), pr.output); 43 | 44 | 45 | pr=ist.parse(TokenList.createD("blah", "isprime", LargeInteger.valueOf(10), "blah"),1); 46 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 47 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", false,"blah"), pr.output); 48 | 49 | pr=ist.parse(TokenList.createD("blah", "isprime", LargeInteger.valueOf(29), "blah"),1); 50 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 51 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", true,"blah"), pr.output); 52 | 53 | pr=ist.parse(TokenList.createD("blah", "isprime", LargeInteger.valueOf(100), "blah"),1); 54 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 55 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", false,"blah"), pr.output); 56 | 57 | pr=ist.parse(TokenList.createD("blah", "isprime", LargeInteger.valueOf(7919 ), "blah"),1); 58 | Assert.assertTrue("Ensure parse was successful: ", pr.isSuccess()); 59 | Assert.assertEquals("Ensure parse result is what it's supposed to be: ",TokenList.createD("blah", true,"blah"), pr.output); 60 | 61 | 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/lastcalc/parsers/UserDefinedParserParserTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers; 17 | 18 | import java.util.*; 19 | 20 | import junit.framework.Assert; 21 | 22 | import com.google.common.collect.*; 23 | 24 | import org.junit.Test; 25 | 26 | public class UserDefinedParserParserTest { 27 | 28 | @Test 29 | public void bindMapTest() throws Exception { 30 | final PreParser.MapWithTail mwt = new PreParser.MapWithTail(Maps.newLinkedHashMap(), "tailvar"); 31 | mwt.map.put("key1", "value1var"); 32 | mwt.map.put("key2var", "value2var"); 33 | final Set variables = Sets.newHashSet("value1var", "key2var", "value2var", "tailvar"); 34 | final LinkedHashMap bindMap = Maps.newLinkedHashMap(); 35 | bindMap.put("key1", "value1"); 36 | bindMap.put("key2", "value2"); 37 | bindMap.put("key3", "value3"); 38 | final Map bound = Maps.newHashMap(); 39 | UserDefinedParserParser.bind(mwt, bindMap, variables, bound); 40 | Assert.assertEquals(variables.size(), bound.size()); 41 | Assert.assertEquals("value1", bound.get("value1var")); 42 | Assert.assertEquals("key2", bound.get("key2var")); 43 | Assert.assertEquals("value2", bound.get("value2var")); 44 | Assert.assertTrue(bound.get("tailvar") instanceof Map); 45 | final Map tailMap = (Map) bound.get("tailvar"); 46 | Assert.assertEquals(1, tailMap.size()); 47 | Assert.assertEquals("value3", tailMap.get("key3")); 48 | 49 | // TODO: Test with just map, rather than MapWithTail 50 | } 51 | 52 | @Test 53 | public void bindListTest() throws Exception { 54 | final PreParser.ListWithTail lwt = new PreParser.ListWithTail(Lists. newArrayList("var1", "var2", 55 | "var3"), "tailvar"); 56 | final List bindList = Lists. newArrayList("val1", "val2", "val3", "val4"); 57 | final Set variables = Sets.newHashSet("var1", "var2", "var3", "tailvar"); 58 | final LinkedHashMap bindMap = Maps.newLinkedHashMap(); 59 | final Map bound = Maps.newHashMap(); 60 | UserDefinedParserParser.bind(lwt, bindList, variables, bound); 61 | Assert.assertEquals(variables.size(), bound.size()); 62 | Assert.assertEquals("val1", bound.get("var1")); 63 | Assert.assertEquals("val2", bound.get("var2")); 64 | Assert.assertEquals("val3", bound.get("var3")); 65 | Assert.assertTrue(bound.get("tailvar") instanceof List); 66 | final List tailList = (List) bound.get("tailvar"); 67 | Assert.assertEquals(1, tailList.size()); 68 | Assert.assertEquals("val4", tailList.get(0)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/engines/ParseStep.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.engines; 17 | 18 | import com.lastcalc.TokenList; 19 | import com.lastcalc.parsers.*; 20 | import com.lastcalc.parsers.Parser.ParseResult; 21 | import com.lastcalc.parsers.UserDefinedParserParser.UserDefinedParser; 22 | 23 | public class ParseStep implements Comparable { 24 | public final TokenList input; 25 | 26 | public final ParseResult result; 27 | 28 | public final Parser parser; 29 | 30 | public final ParseStep previous; 31 | 32 | public final int depth; 33 | 34 | public final double scoreBias; 35 | 36 | public ParseStep(final TokenList input, final Parser parser, final ParseResult result, final ParseStep previous, 37 | final double score) { 38 | this.input = input; 39 | this.parser = parser; 40 | scoreBias = (previous == null ? 0 : previous.scoreBias) + score; 41 | this.result = result; 42 | this.previous = previous; 43 | if (previous != null) { 44 | depth = previous.depth + 1; 45 | } else { 46 | depth = 0; 47 | } 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return getScore() + "\t" + parser.getClass().getSimpleName() + "\t" + input + "\t" + result.output; 53 | } 54 | 55 | @Override 56 | public int compareTo(final ParseStep other) { 57 | if (getScore() < other.getScore()) 58 | return -1; 59 | else if (getScore() > other.getScore()) 60 | return 1; 61 | else if (hashCode() < other.hashCode()) 62 | return -1; 63 | else if (hashCode() > other.hashCode()) 64 | return 1; 65 | else 66 | return 0; 67 | } 68 | 69 | private double cachedScore = Double.MAX_VALUE; 70 | 71 | private double getScore() { 72 | if (cachedScore == Double.MAX_VALUE) { 73 | cachedScore = scoreBias + getScore(result.output) - (0.0001 * depth); 74 | } 75 | return cachedScore; 76 | } 77 | 78 | public static double getScore(final Object token) { 79 | double score = 0; 80 | if (token instanceof TokenList) { 81 | for (final Object t : ((TokenList) token)) { 82 | if (t instanceof String) { 83 | score++; 84 | } else if (t instanceof Number) { 85 | score += 0.8; 86 | } else { 87 | score += 0.5; 88 | } 89 | } 90 | } 91 | return score; 92 | } 93 | 94 | public boolean isMinimal() { 95 | if (result.output.size() == 1 && !(result.output.get(0) instanceof String)) { 96 | if (result.output.get(0) instanceof UserDefinedParser) { 97 | final UserDefinedParser udp = (UserDefinedParser) result.output.get(0); 98 | // Handle a common case 99 | if (udp.getTemplate().indexOf("if") != -1) 100 | return false; 101 | else 102 | return true; 103 | } else 104 | return true; 105 | } else 106 | return false; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/math/IsPrimeParser.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.math; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.lastcalc.TokenList; 5 | import com.lastcalc.parsers.Parser; 6 | import org.jscience.mathematics.number.LargeInteger; 7 | 8 | 9 | /** 10 | * **************************************************************************** 11 | * LastCalc - The last calculator you'll ever need 12 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 13 | *

14 | * This program is free software: you can redistribute it and/or modify it 15 | * under the terms of the GNU Affero General Public License as published 16 | * by the Free Software Foundation, either version 3 of the License, or 17 | * (at your option) any later version. 18 | *

19 | * This program is distributed in the hope that it will be useful, but 20 | * WITHOUT ANY WARRANTY; without even the implied warranty of 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 22 | * PURPOSE. See the GNU Affero General Public License for more 23 | * details. 24 | * **************************************************************************** 25 | */ 26 | public class IsPrimeParser extends Parser { 27 | 28 | private static TokenList template = TokenList.createD(Lists. newArrayList("isprime"),Number.class); 29 | 30 | @Override 31 | public TokenList getTemplate() { 32 | return template; 33 | } 34 | 35 | 36 | @Override 37 | public ParseResult parse(final TokenList tokens, final int templatePos) { 38 | 39 | final String op = (String) tokens.get(templatePos); 40 | final Integer input = ((LargeInteger)tokens.get(templatePos + 1)).intValue(); 41 | 42 | 43 | if(op.equals("isprime")){ 44 | 45 | //first, we check if the number is greater than the last element of the primeslist. 46 | 47 | //if yes, then we expand the primeslist to be big enough until the last element 48 | // of the primeslist is the largest prime that is still less than the input number. if the input number is prime 49 | // then return true else false 50 | 51 | 52 | //if the input number is less than the last element of the primeslist, then we see if it is in the primeslist 53 | 54 | //if it's there then it's prime, if not the false. 55 | 56 | 57 | //run the sqrt n primality test algorithm 58 | 59 | final Integer inputSqrRoot=(int)Math.sqrt((double)input); 60 | 61 | if(input ==1){ 62 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), false)); 63 | } 64 | else if(input==2 || input==3){ 65 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), true)); 66 | } 67 | 68 | for(int i=2;i<=inputSqrRoot;i++){ 69 | if(input%i==0){ 70 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), false)); 71 | } 72 | } 73 | 74 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), true)); 75 | 76 | } 77 | else{ 78 | return ParseResult.fail(); 79 | } 80 | } 81 | 82 | @Override 83 | public int hashCode() { 84 | return 0; 85 | } 86 | 87 | @Override 88 | public boolean equals(Object obj) { 89 | return false; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/engines/BacktrackingParseEngine.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.engines; 17 | 18 | import java.util.*; 19 | 20 | import com.google.common.collect.*; 21 | 22 | import com.lastcalc.TokenList; 23 | import com.lastcalc.engines.ParserPickerFactory.ParserPicker; 24 | import com.lastcalc.parsers.*; 25 | import com.lastcalc.parsers.Parser.ParseResult; 26 | 27 | 28 | public class BacktrackingParseEngine extends ParseEngine { 29 | 30 | private final ParserPickerFactory ppf; 31 | 32 | public BacktrackingParseEngine(final ParserPickerFactory ppf) { 33 | this.ppf = ppf; 34 | 35 | } 36 | 37 | private int lastParseStepCount = 0; 38 | 39 | private boolean dumpSteps = false; 40 | 41 | public void setDumpSteps(final boolean dumpSteps) { 42 | this.dumpSteps = dumpSteps; 43 | } 44 | 45 | @Override 46 | public LinkedList parse(final TokenList input, 47 | final ParserContext context, 48 | final TokenList... alternateInputs) { 49 | lastParseStepCount = 0; 50 | final TreeSet candidates = Sets. newTreeSet(); 51 | final ParserPicker picker = ppf.getPicker(); 52 | candidates.add(new ParseStep(input, NoopParser.singleton, ParseResult.success(input), null, 0)); 53 | for (final TokenList alternateTL : alternateInputs) { 54 | candidates.add(new ParseStep(alternateTL, NoopParser.singleton, ParseResult.success(alternateTL), null, 0)); 55 | } 56 | final long startTime = System.currentTimeMillis(); 57 | ParserContext subContext; 58 | try { 59 | subContext = (ParserContext) context.clone(); 60 | } catch (final CloneNotSupportedException e) { 61 | throw new RuntimeException(e); 62 | } 63 | subContext.timeout = context.timeout / 5; 64 | final Set exhausted = Sets.newHashSet(); 65 | outer: while (System.currentTimeMillis() - startTime < context.timeout && !candidates.first().isMinimal()) { 66 | for (final ParseStep candidateStep : candidates) { 67 | if (exhausted.contains(candidateStep)) { 68 | continue; 69 | } 70 | final ParseStep nextStep = picker.pickNext(subContext, candidateStep); 71 | if (nextStep != null && nextStep.result.isSuccess()) { 72 | lastParseStepCount++; 73 | if (dumpSteps) { 74 | System.out.println(lastParseStepCount + "\t" + nextStep); 75 | } 76 | candidates.add(nextStep); 77 | continue outer; 78 | } else { 79 | exhausted.add(candidateStep); 80 | } 81 | } 82 | break outer; 83 | } 84 | final LinkedList steps = Lists.newLinkedList(); 85 | ParseStep bestStep = candidates.first(); 86 | 87 | bestStep.isMinimal(); 88 | 89 | while (bestStep != null) { 90 | steps.addFirst(bestStep); 91 | bestStep = bestStep.previous; 92 | } 93 | 94 | return steps; 95 | } 96 | 97 | public int getLastParseStepCount() { 98 | return lastParseStepCount; 99 | } 100 | } 101 | 102 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/currency/Currencies.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.parsers.currency; 17 | 18 | import java.io.InputStreamReader; 19 | import java.net.URL; 20 | import java.util.*; 21 | import java.util.Map.Entry; 22 | import java.util.logging.Logger; 23 | 24 | import com.google.common.collect.*; 25 | 26 | import org.jscience.economics.money.Currency; 27 | 28 | import com.lastcalc.*; 29 | import com.lastcalc.parsers.Parser; 30 | import com.lastcalc.parsers.amounts.UnitParser; 31 | 32 | public class Currencies { 33 | private static final Logger log = Logger.getLogger(Currencies.class.getName()); 34 | 35 | public static long lastExchangeRateUpdateAttempt = 0; 36 | 37 | public static volatile Map currenciesByCode; 38 | 39 | public static boolean shouldUpdate() { 40 | return System.currentTimeMillis() - lastExchangeRateUpdateAttempt > 60l * 60l * 1000l; 41 | } 42 | 43 | public static List getParsers() { 44 | if (currenciesByCode == null) { 45 | updateExchangeRates(); 46 | } 47 | final LinkedList parsers = Lists.newLinkedList(); 48 | if (currenciesByCode != null) { 49 | for (final Entry e : currenciesByCode.entrySet()) { 50 | parsers.add(new UnitParser(e.getValue(), TokenList.createD(e.getKey()))); 51 | parsers.add(new UnitParser(e.getValue(), TokenList.createD(e.getKey().toLowerCase()))); 52 | } 53 | parsers.add(new UnitParser(currenciesByCode.get("USD"), TokenList.createD("$"))); 54 | parsers.add(new UnitParser(currenciesByCode.get("EUR"), TokenList.createD("�"))); 55 | parsers.add(new UnitParser(currenciesByCode.get("JPY"), TokenList.createD("�"))); 56 | parsers.add(new UnitParser(currenciesByCode.get("GBP"), TokenList.createD("�"))); 57 | 58 | parsers.add(new CurrencyReverser()); 59 | } 60 | 61 | return parsers; 62 | } 63 | 64 | public static void updateExchangeRates() { 65 | Currency.setReferenceCurrency(Currency.USD); 66 | try { 67 | final URL url = new URL("http://openexchangerates.org/api/latest.json?app_id=d1bd706a92774feca9c15d615ae85685"); 68 | final Rates rates = Misc.gson.fromJson(new InputStreamReader(url.openStream()), Rates.class); 69 | if (!rates.base.equalsIgnoreCase("usd")) { 70 | log.warning("We assume base rate of USD, but it is " + rates.base); 71 | } 72 | final Map currencies = Maps.newHashMap(); 73 | for (final Entry e : rates.rates.entrySet()) { 74 | final Currency currency = new Currency(e.getKey()); 75 | currency.setExchangeRate(1.0 / e.getValue()); 76 | currencies.put(e.getKey(), currency); 77 | } 78 | 79 | currenciesByCode = currencies; 80 | } catch (final Exception e) { 81 | log.warning("Couldn't update currency conversion rates " + e); 82 | e.printStackTrace(); 83 | } 84 | lastExchangeRateUpdateAttempt = System.currentTimeMillis(); 85 | } 86 | 87 | public static class Rates { 88 | public String base; 89 | public Map rates; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/math/PrimesUnderParser.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.math; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.lastcalc.TokenList; 5 | import com.lastcalc.bootstrap.Bootstrap; 6 | import com.lastcalc.parsers.Parser; 7 | import org.jscience.mathematics.number.*; 8 | import org.jscience.mathematics.number.Number; 9 | 10 | import java.io.*; 11 | import java.util.ArrayList; 12 | import java.util.Iterator; 13 | 14 | /** 15 | * **************************************************************************** 16 | * LastCalc - The last calculator you'll ever need 17 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 18 | *

19 | * This program is free software: you can redistribute it and/or modify it 20 | * under the terms of the GNU Affero General Public License as published 21 | * by the Free Software Foundation, either version 3 of the License, or 22 | * (at your option) any later version. 23 | *

24 | * This program is distributed in the hope that it will be useful, but 25 | * WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 27 | * PURPOSE. See the GNU Affero General Public License for more 28 | * details. 29 | * **************************************************************************** 30 | */ 31 | public class PrimesUnderParser extends Parser { 32 | 33 | //all the primes under 1000. This parser doesnt work for numbers above 1000 34 | final private ArrayList allprimes=new ArrayList(); 35 | 36 | 37 | 38 | private static TokenList template = TokenList.createD(Lists. newArrayList("primesunder"),Number.class); 39 | 40 | @Override 41 | public TokenList getTemplate() { 42 | return template; 43 | } 44 | 45 | public PrimesUnderParser(){//put the primes into the array list 46 | 47 | final BufferedReader br; 48 | final String [] primesString; 49 | try{ 50 | br = new BufferedReader(new InputStreamReader( 51 | Bootstrap.class.getResourceAsStream("prime_numbers.txt"))); 52 | //found in src/main/resources/com/lastcalc/bootstrap/prime_numbers.txt 53 | 54 | primesString = br.readLine().split(", "); 55 | } 56 | catch(Exception e){ 57 | System.err.println("prime_numbers.txt input error"); 58 | return; 59 | } 60 | 61 | for(int i=0;i allprimesiterator = allprimes.iterator(); 77 | 78 | ArrayList resultList=new ArrayList(); 79 | 80 | Integer i=allprimesiterator.next(); 81 | while(allprimesiterator.hasNext() && i<=input){ 82 | resultList.add(i); 83 | i=allprimesiterator.next(); 84 | } 85 | 86 | return ParseResult.success(tokens.replaceWithTokens(templatePos, templatePos + template.size(), resultList)); 87 | } 88 | return ParseResult.fail(); 89 | } 90 | 91 | 92 | @Override 93 | public int hashCode() { 94 | return 0; //To change body of implemented methods use File | Settings | File Templates. 95 | } 96 | 97 | @Override 98 | public boolean equals(Object obj) { 99 | return false; //To change body of implemented methods use File | Settings | File Templates. 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/cache/ObjectCache.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * LastCalc - The last calculator you'll ever need 3 | * Copyright (C) 2011, 2012 Uprizer Labs LLC 4 | * 5 | * This program is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 | * PURPOSE. See the GNU Affero General Public License for more 14 | * details. 15 | ******************************************************************************/ 16 | package com.lastcalc.cache; 17 | 18 | import java.io.Serializable; 19 | import java.util.*; 20 | import java.util.logging.Logger; 21 | 22 | import javax.cache.*; 23 | 24 | import com.google.common.collect.*; 25 | 26 | import com.google.appengine.api.memcache.jsr107cache.GCacheFactory; 27 | 28 | public class ObjectCache { 29 | private static final Logger log = Logger.getLogger(ObjectCache.class.getName()); 30 | 31 | static Map softMap = new MapMaker().softValues().makeMap(); 32 | 33 | public static T getFast(final long oldestAllowed, final Object... key) { 34 | return getFastWithHash(oldestAllowed, Arrays.hashCode(key)); 35 | } 36 | 37 | @SuppressWarnings("unchecked") 38 | private static T getFastWithHash(final long oldestAllowed, final int hash) { 39 | final CachedObject co = softMap.get(hash); 40 | if (co == null) 41 | return null; 42 | if (System.currentTimeMillis() - oldestAllowed > co.cacheTime) 43 | return (T) co.object; 44 | else 45 | return null; 46 | } 47 | 48 | @SuppressWarnings("unchecked") 49 | public static T getSlow(final long oldestAllowed, final Object... key) { 50 | final int keyHash = Arrays.hashCode(key); 51 | final T o = getFastWithHash(oldestAllowed, keyHash); 52 | if (o != null) { 53 | log.info("Got from local RAM"); 54 | return o; 55 | } 56 | else { 57 | CacheFactory cacheFactory; 58 | try { 59 | cacheFactory = CacheManager.getInstance().getCacheFactory(); 60 | final Cache memcache = cacheFactory.createCache(Collections.emptyMap()); 61 | final CachedObject co = (CachedObject) memcache.get(keyHash); 62 | if (co != null) { 63 | log.info("Got from memcache"); 64 | return (T) co.object; 65 | } 66 | else 67 | return null; 68 | } catch (final CacheException e) { 69 | log.warning("Exception retrieving object from cache: " + e); 70 | return null; 71 | } 72 | } 73 | } 74 | 75 | @SuppressWarnings("unchecked") 76 | public static void put(final long expirationDelta, final Object value, final Object... key) { 77 | final int keyHash = Arrays.hashCode(key); 78 | final CachedObject co = new CachedObject(value); 79 | softMap.put(keyHash, co); 80 | CacheFactory cacheFactory; 81 | try { 82 | cacheFactory = CacheManager.getInstance().getCacheFactory(); 83 | final Map props = Maps.newHashMap(); 84 | props.put(GCacheFactory.EXPIRATION_DELTA, 3600); 85 | final Cache memcache = cacheFactory.createCache(props); 86 | memcache.put(keyHash, co); 87 | } catch (final CacheException e) { 88 | log.warning("Exception retrieving object from cache: " + e); 89 | } 90 | } 91 | 92 | public static class CachedObject implements Serializable { 93 | /** 94 | * 95 | */ 96 | private static final long serialVersionUID = 2851269118906160513L; 97 | 98 | public final long cacheTime; 99 | 100 | public final Object object; 101 | 102 | public CachedObject(final Object object) { 103 | this.object = object; 104 | cacheTime = System.currentTimeMillis(); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/lastcalc/parsers/meta/ImportParser.java: -------------------------------------------------------------------------------- 1 | package com.lastcalc.parsers.meta; 2 | 3 | import java.io.*; 4 | import java.net.*; 5 | import java.util.Collection; 6 | 7 | import com.lastcalc.*; 8 | import com.lastcalc.Tokenizer.QuotedString; 9 | import com.lastcalc.cache.ObjectCache; 10 | import com.lastcalc.parsers.*; 11 | 12 | public class ImportParser extends Parser { 13 | 14 | private static TokenList template = TokenList.createD("import", QuotedString.class); 15 | 16 | @Override 17 | public TokenList getTemplate() { 18 | return template; 19 | } 20 | @Override 21 | public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) { 22 | if (context.importDepth > 5) 23 | return ParseResult.fail(); 24 | URL url; 25 | try { 26 | url = new URL(((QuotedString) tokens.get(templatePos + 1)).value); 27 | } catch (final MalformedURLException e) { 28 | return ParseResult.fail(); 29 | } 30 | 31 | CachedImport cached = ObjectCache.getSlow(1000l * 60l * 60l * 24l, url); 32 | 33 | if (cached == null || 34 | (System.currentTimeMillis() > cached.expires && System.currentTimeMillis() - cached.currentAt > 60l*1000l)) { 35 | // More than a minute ago and after expires time, let's check to see 36 | // whether the original URL is updated 37 | try { 38 | final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 39 | connection.setRequestProperty("Accept", "text/plain"); 40 | if (cached != null && cached.lastModifiedHeader != null) { 41 | connection.setRequestProperty("If-Modified-Since", cached.lastModifiedHeader); 42 | } 43 | if (cached != null && cached.eTag != null) { 44 | connection.setRequestProperty("If-None-Match", cached.eTag); 45 | } 46 | final int code = connection.getResponseCode(); 47 | if (code == 304) { 48 | // It was cached, update 49 | cached.currentAt = System.currentTimeMillis(); 50 | ObjectCache.put(1000l * 60l * 60l * 24l, cached, url); 51 | } else { 52 | final String contentType = connection.getContentType(); 53 | if (contentType.toLowerCase().contains("text/plain")) { 54 | cached = new CachedImport(); 55 | final BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); 56 | final ParserContext pc = new ParserContext(context.parseEngine, context.timeout, context.importDepth + 1); 57 | final SequentialParser sp = SequentialParser.create(pc); 58 | while (true) { 59 | final String nextLine = br.readLine(); 60 | if (nextLine == null) { 61 | break; 62 | } 63 | sp.parseNext(nextLine); 64 | } 65 | 66 | cached = new CachedImport(); 67 | 68 | cached.userDefinedParsers = sp.getUserDefinedParsers().getParsers(); 69 | cached.currentAt = System.currentTimeMillis(); 70 | cached.lastModifiedHeader = connection.getHeaderField("Last-Modified"); 71 | cached.eTag = connection.getHeaderField("ETag"); 72 | cached.expires = connection.getHeaderFieldDate("Expires", 0); 73 | ObjectCache.put(1000l * 60l * 60l * 24l, cached, url); 74 | 75 | } else 76 | return ParseResult.fail(); 77 | } 78 | 79 | } catch (final IOException e) { 80 | return ParseResult.fail(); 81 | } 82 | } 83 | 84 | return ParseResult.success(tokens.replaceWithTokens(templatePos, template.size(), cached.userDefinedParsers)); 85 | } 86 | 87 | @Override 88 | public int hashCode() { 89 | // TODO Auto-generated method stub 90 | return 0; 91 | } 92 | 93 | @Override 94 | public boolean equals(final Object obj) { 95 | // TODO Auto-generated method stub 96 | return false; 97 | } 98 | 99 | public static class CachedImport implements Serializable { 100 | private static final long serialVersionUID = -3304707639237443710L; 101 | public long currentAt, expires; 102 | 103 | public String eTag; 104 | 105 | public String lastModifiedHeader; 106 | 107 | public Collection userDefinedParsers; 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /src/main/webapp/css/highlighting.css: -------------------------------------------------------------------------------- 1 | .number { 2 | color: #229; 3 | } 4 | 5 | .quoted { 6 | color: #229999; 7 | } 8 | 9 | .recognized { 10 | color: #777777; 11 | } 12 | 13 | .variable { 14 | display: inline-block; 15 | outline: none; 16 | text-align: center; 17 | font-size: 14px; 18 | padding-top: 0px; 19 | padding-bottom: 2px; 20 | padding-left: 2px; 21 | padding-right: 2px; 22 | text-shadow: 0 1px 1px rgba(0, 0, 0, .3); 23 | -webkit-border-radius: .5em; 24 | -moz-border-radius: .5em; 25 | border-radius: .5em; 26 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .2); 27 | -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, .2); 28 | box-shadow: 0 1px 2px rgba(0, 0, 0, .2); 29 | } 30 | 31 | .black { 32 | color: #d7d7d7; 33 | border: solid 1px #333; 34 | background: #333; 35 | background: -webkit-gradient(linear, left top, left bottom, from(#666), 36 | to(#000) ); 37 | background: -moz-linear-gradient(top, #666, #000); 38 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#666666', 39 | endColorstr='#000000' ); 40 | } 41 | 42 | .gray { 43 | color: #e9e9e9; 44 | border: solid 1px #555; 45 | background: #6e6e6e; 46 | background: -webkit-gradient(linear, left top, left bottom, from(#888), 47 | to(#575757) ); 48 | background: -moz-linear-gradient(top, #888, #575757); 49 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#888888', 50 | endColorstr='#575757' ); 51 | } 52 | 53 | .white { 54 | color: #606060; 55 | border: solid 1px #b7b7b7; 56 | background: #fff; 57 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), 58 | to(#ededed) ); 59 | background: -moz-linear-gradient(top, #fff, #ededed); 60 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', 61 | endColorstr='#ededed' ); 62 | } 63 | 64 | .orange { 65 | color: #fef4e9; 66 | border: solid 1px #da7c0c; 67 | background: #f78d1d; 68 | background: -webkit-gradient(linear, left top, left bottom, from(#faa51a), 69 | to(#f47a20) ); 70 | background: -moz-linear-gradient(top, #faa51a, #f47a20); 71 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#faa51a', 72 | endColorstr='#f47a20' ); 73 | } 74 | 75 | .red { 76 | color: #faddde; 77 | border: solid 1px #980c10; 78 | background: #d81b21; 79 | background: -webkit-gradient(linear, left top, left bottom, from(#ed1c24), 80 | to(#aa1317) ); 81 | background: -moz-linear-gradient(top, #ed1c24, #aa1317); 82 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ed1c24', 83 | endColorstr='#aa1317' ); 84 | } 85 | 86 | .blue { 87 | color: #d9eef7; 88 | border: solid 1px #0076a3; 89 | background: #0095cd; 90 | background: -webkit-gradient(linear, left top, left bottom, from(#00adee), 91 | to(#0078a5) ); 92 | background: -moz-linear-gradient(top, #00adee, #0078a5); 93 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', 94 | endColorstr='#0078a5' ); 95 | } 96 | 97 | .rosy { 98 | color: #fae7e9; 99 | border: solid 1px #b73948; 100 | background: #da5867; 101 | background: -webkit-gradient(linear, left top, left bottom, from(#f16c7c), 102 | to(#bf404f) ); 103 | background: -moz-linear-gradient(top, #f16c7c, #bf404f); 104 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f16c7c', 105 | endColorstr='#bf404f' ); 106 | } 107 | 108 | .green { 109 | color: #e8f0de; 110 | border: solid 1px #538312; 111 | background: #64991e; 112 | background: -webkit-gradient(linear, left top, left bottom, from(#7db72f), 113 | to(#4e7d0e) ); 114 | background: -moz-linear-gradient(top, #7db72f, #4e7d0e); 115 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#7db72f', 116 | endColorstr='#4e7d0e' ); 117 | } 118 | 119 | .pink { 120 | color: #feeef5; 121 | border: solid 1px #d2729e; 122 | background: #f895c2; 123 | background: -webkit-gradient(linear, left top, left bottom, from(#feb1d3), 124 | to(#f171ab) ); 125 | background: -moz-linear-gradient(top, #feb1d3, #f171ab); 126 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#feb1d3', 127 | endColorstr='#f171ab' ); 128 | } 129 | -------------------------------------------------------------------------------- /src/main/webapp/js/rangy-serializer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Serializer module for Rangy. 3 | Serializes Ranges and Selections. An example use would be to store a user's selection on a particular page in a 4 | cookie or local storage and restore it on the user's next visit to the same page. 5 | 6 | Part of Rangy, a cross-browser JavaScript range and selection library 7 | http://code.google.com/p/rangy/ 8 | 9 | Depends on Rangy core. 10 | 11 | Copyright 2011, Tim Down 12 | Licensed under the MIT license. 13 | Version: 1.2.2 14 | Build date: 13 November 2011 15 | */ 16 | rangy.createModule("Serializer",function(g,n){function o(c,a){a=a||[];var b=c.nodeType,e=c.childNodes,d=e.length,f=[b,c.nodeName,d].join(":"),h="",k="";switch(b){case 3:h=c.nodeValue.replace(//g,">");break;case 8:h="