├── .gitignore ├── LICENSE.md ├── README.md ├── src └── com │ └── mauriciotogneri │ └── jan │ ├── bytecode │ ├── Compiler.java │ ├── MyClass.java │ └── Runtime.java │ ├── compiler │ ├── Compiler.java │ ├── lexical │ │ ├── Character.java │ │ ├── LexicalAnalyzer.java │ │ ├── LexicalException.java │ │ ├── State.java │ │ ├── StateMachine.java │ │ ├── Token.java │ │ └── states │ │ │ ├── AddState.java │ │ │ ├── CommentState.java │ │ │ ├── DecrementState.java │ │ │ ├── FloatState.java │ │ │ ├── GreaterEqualState.java │ │ │ ├── GreaterState.java │ │ │ ├── IfElseState.java │ │ │ ├── IfState.java │ │ │ ├── IncrementState.java │ │ │ ├── InitialState.java │ │ │ ├── IntegerState.java │ │ │ ├── LessEqualState.java │ │ │ ├── LessState.java │ │ │ ├── NegationState.java │ │ │ ├── NotEqualState.java │ │ │ ├── OperatorState.java │ │ │ ├── StringEndState.java │ │ │ ├── StringEscapeState.java │ │ │ ├── StringState.java │ │ │ ├── SubtractState.java │ │ │ └── SymbolState.java │ ├── semantic │ │ ├── SemanticAnalyzer.java │ │ └── SemanticException.java │ └── syntactic │ │ ├── State.java │ │ ├── StateMachine.java │ │ ├── SyntacticAnalyzer.java │ │ ├── SyntacticException.java │ │ └── states │ │ ├── AnonymousExpressionEndState.java │ │ ├── AnonymousExpressionStartState.java │ │ ├── AnonymousFunctionState.java │ │ ├── ExpressionEndState.java │ │ ├── ExpressionStartState.java │ │ ├── FunctionDefinedState.java │ │ ├── FunctionDefinitionState.java │ │ ├── FunctionParameterEndState.java │ │ ├── FunctionParameterStartState.java │ │ ├── ImportEndState.java │ │ ├── ImportStartState.java │ │ ├── ImportState.java │ │ └── InitialState.java │ ├── execution │ ├── input │ │ ├── DefaultProgramInput.java │ │ └── ProgramInput.java │ └── output │ │ ├── DefaultProgramOutput.java │ │ └── ProgramOutput.java │ └── kernel │ ├── Context.java │ ├── Expression.java │ ├── Function.java │ ├── Jan.java │ ├── Node.java │ ├── Parameters.java │ ├── Program.java │ ├── Value.java │ └── nodes │ ├── FunctionNode.java │ ├── ListNode.java │ ├── LiteralNode.java │ ├── OperatorNode.java │ ├── ParameterNode.java │ ├── PrimitiveNode.java │ ├── arithmetic │ ├── AddNode.java │ ├── DecrementNode.java │ ├── DivisionNode.java │ ├── IncrementNode.java │ ├── ModuleNode.java │ ├── MultiplicationNode.java │ ├── PowerNode.java │ └── SubtractNode.java │ ├── array │ ├── IndexNode.java │ ├── LengthNode.java │ └── RemoveNode.java │ ├── conditional │ ├── IfElseNode.java │ └── IfNode.java │ ├── list │ ├── ListCloseNode.java │ └── ListOpenNode.java │ ├── logic │ ├── AndNode.java │ ├── EqualNode.java │ ├── GreaterEqualNode.java │ ├── GreaterNode.java │ ├── LessEqualNode.java │ ├── LessNode.java │ ├── NegationNode.java │ ├── NotEqualNode.java │ └── OrNode.java │ └── operations │ ├── BinaryBooleanNode.java │ ├── BinaryNode.java │ ├── BinaryNumericNode.java │ ├── UnaryBooleanNode.java │ └── UnaryNumericNode.java └── tests ├── com └── mauriciotogneri │ └── jan │ └── tests │ ├── CustomProgramOutput.java │ └── Tests.java ├── samples ├── bool.jan ├── list.jan ├── math.jan └── sample.jan └── scripts ├── test_boolean.jan ├── test_float.jan └── test_integer.jan /.gitignore: -------------------------------------------------------------------------------- 1 | /out 2 | /.idea 3 | Jan.iml -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mauricio Togneri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JAN 2 | 3 | 4 | 5 | **Jan** is a purely functional programming language with an ultra minimalist syntax. It is named after **Jan Łukasiewicz**, a Polish logician and philosopher creator of the **Polish notation**, also known as **Prefix notation**, which is a form of notation for logic, arithmetic and algebra. The distinguishing feature of this language is that it places operators to the left of their operands. Given that the arity of the operators and functions in the language is fixed, the result is a syntax lacking parentheses or other brackets that can still be parsed without ambiguity. Although **Jan** is a general purpose language, it is mostly intended to be used as a tool for learning functional programming. 6 | 7 | ## Table of Contents 8 | 9 | - [Characteristics](#characteristics) 10 | - [Syntax](#syntax) 11 | - [Functions](#functions) 12 | - [Expressions](#expressions) 13 | - [Operators](#operators) 14 | - [Arithmetic](#arithmetic) 15 | - [Comparison](#comparison) 16 | - [Logical](#logical) 17 | - [Conditional](#conditional) 18 | - [String](#string) 19 | - [List](#list) 20 | - [Import](#import) 21 | - [Comments](#comments) 22 | - [Anonymous function](#anonymous-function) 23 | - [Types](#types) 24 | - [Numbers](#numbers) 25 | - [Booleans](#booleans) 26 | - [Strings](#strings) 27 | - [Lists](#lists) 28 | - [Execution](#execution) 29 | - [Standard Library](#standard-library) 30 | - [Examples](#examples) 31 | 32 | ## Characteristics 33 | 34 | The language has the following characteristics: 35 | 36 | * Purely functional 37 | * All functions and operands use prefix notation 38 | * Interpreted 39 | * Case sensitive 40 | * There are no reserved words 41 | 42 | ## Syntax 43 | 44 | A _program_ written in **Jan** consists of a set of functions. A _function_ consists of a set of expressions that are evaluated sequentially. An _expression_ is a combination of explicit constants, parameters, operators and functions that are evaluated to return a value (or an empty result). The language follows the _off-side_ rule to define its syntax (i.e., blocks are expressed by indentation marks). A **Jan** script should have a **.jan** extension. 45 | 46 | ### Functions 47 | 48 | Functions in **Jan** have a name (unique within the program), a list of parameters (if any) and a list of expressions that will be evaluated sequentially. When a function is called, the interpreter evaluates the expressions in the order that they were defined. If an expression returns a value (i.e., it does not return an empty result), the function finishes and the result of that expression is returned. 49 | 50 | Function template: 51 | 52 | ``` 53 | FUNCTION_NAME PARAMETER_1 PARAMETER_2 PARAMETER_3... 54 | EXPRESSION_1 55 | EXPRESSION_2 56 | EXPRESSION_3 57 | ... 58 | ``` 59 | 60 | Notice that the expressions are indented using the tab character and the formal parameters are not separated by commas but by a whitespace. 61 | 62 | Here is an example function that compares 2 numbers: 63 | 64 | ```common-lisp 65 | compare a b 66 | ? > a b "A is bigger than B" 67 | ? > b a "B is bigger than A" 68 | "A and B are equal" 69 | ``` 70 | 71 | In pseudocode it could be written as: 72 | 73 | ```pascal 74 | function compare (a, b) 75 | if (a > b) then 76 | return "A is bigger than B" 77 | end if 78 | 79 | if (b > a) then 80 | return "B is bigger than A" 81 | end if 82 | 83 | return "A and B are equal" 84 | end 85 | ``` 86 | 87 | ### Expressions 88 | 89 | There are two types of expressions: 90 | 91 | * _Non-Conditional_: these expressions are evaluated and returned as a result. 92 | * _Conditional_: these expressions evaluate a condition in order to determine if a value is returned or not. There are two types of conditional expressions: 93 | 94 | _Simple_: the condition is evaluated and if it is true, the expression returns a value, otherwise the execution continues to the next expression. 95 | 96 | Example: 97 | 98 | ```common-lisp 99 | ? = n 0 "N is zero" 100 | ``` 101 | 102 | The previous expression can be read as: _if n is equal to zero then return the string "N is zero"_ 103 | 104 | In pseudocode it could be written as: 105 | 106 | ```pascal 107 | if (n == 0) then 108 | return "N is zero" 109 | end if 110 | ``` 111 | 112 | _Complex_: the condition is evaluated and if it is true, the expression returns the result of the consequent value, otherwise it returns the result of the alternative value. 113 | 114 | Example: 115 | 116 | ```common-lisp 117 | ?? = n 0 "N is zero" "N is not zero" 118 | ``` 119 | 120 | The previous expression can be read as: _if n is equal to zero then return the string "N is zero", otherwise return the string "N is not zero"_ 121 | 122 | In pseudocode it could be written as: 123 | 124 | ```pascal 125 | if (n == 0) then 126 | return "N is zero" 127 | else 128 | return "N is not zero" 129 | end if 130 | ``` 131 | 132 | All functions must contain at least one expression and the last (and only the last) expression in the list must be: 133 | 134 | * A non-conditional expression 135 | * A complex conditional expression 136 | 137 | Expressions must be written using **prefix notation** (i.e., operators are placed to the left of the operands) and there must be at least one whitespace between operators and operands. 138 | 139 | ## Operators 140 | 141 | **Jan** contains a set of built-in operators to be used within expressions: 142 | 143 | ### Arithmetic 144 | 145 | The language supports the following arithmetic operators: 146 | 147 | * Addition: ``+`` 148 | * Example: ``+ a b`` 149 | 150 | * Subtraction: ``-`` 151 | * Example: ``- a b`` 152 | 153 | * Multiplication: ``*`` 154 | * Example: ``* a b`` 155 | 156 | * Division: ``/`` 157 | * Example: ``/ a b`` 158 | 159 | * Increment: ``++`` 160 | * Example: ``++ a`` 161 | 162 | * Decrement: ``--`` 163 | * Example: ``-- a`` 164 | 165 | * Exponentiation: ``^`` 166 | * Example: ``^ a b`` 167 | 168 | * Modulus: ``%`` 169 | * Example: ``% a b`` 170 | 171 | All the arithmetic operators receive numbers as input and return a number as a result. 172 | 173 | ### Comparison 174 | 175 | The language supports the following comparison operators: 176 | 177 | * Equal: ``=`` 178 | * Example: ``= a b`` 179 | 180 | * Not equal: ``!=`` 181 | * Example: ``!= a b`` 182 | 183 | These two comparison operators receive either two numbers, two booleans, two strings or two lists as input and return a boolean as a result. 184 | 185 | * Less: ``<`` 186 | * Example: ``< a b`` 187 | 188 | * Less or equal: ``<=`` 189 | * Example: ``<= a b`` 190 | 191 | * Greater: ``>`` 192 | * Example: ``> a b`` 193 | 194 | * Greater or equal: ``>=`` 195 | * Example: ``>= a b`` 196 | 197 | The rest of comparison operators receive two numbers as input an return a boolean as a result. 198 | 199 | ### Logical 200 | 201 | The language supports the following logical operators: 202 | 203 | * And: ``&`` 204 | * Example: ``& a b`` 205 | 206 | * Or: ``|`` 207 | * Example: ``| a b`` 208 | 209 | * Negation: ``!`` 210 | * Example: ``! a`` 211 | 212 | All logical operators receive booleans as input and return a boolean as a result. 213 | 214 | ### Conditional 215 | 216 | The language supports the following conditional operators: 217 | 218 | * Simple conditional: ``?`` 219 | * Example: ``? a b`` (_if **a** then **b**_) 220 | 221 | * Complex conditional: ``??`` 222 | * Example: ``?? a b c`` (_if **a** then **b** else **c**_) 223 | 224 | In both conditional operators, the result of evaluating the first expression (in the examples: **a**) must be a boolean value. 225 | 226 | ### String 227 | 228 | The language supports the following string operators: 229 | 230 | * Definition: ``""`` 231 | * Example: ``"This is an example"`` 232 | 233 | * Indexation: ``@`` 234 | * Example: ``@ 7 "Hello, world!"`` (it returns the 8th character in the string, in the example: **w**) 235 | 236 | * Removal: ``~`` 237 | * Example: ``~ 5 "Do not test me"`` (it removes the 6th character in the string, in the example: **"Do no test me"**) 238 | 239 | * Length: ``#`` 240 | * Example: ``# "The cake is a lie"`` (it returns the length of the string, in the example: **17**) 241 | 242 | * Concatenation: ``+`` 243 | * Example: ``+ "Keep it simple " "and short"`` (it concatenates the two strings, in the example: **"Keep it simple and short"**) 244 | 245 | ### List 246 | 247 | The language supports the following list operators: 248 | 249 | * Definition: ``[]`` 250 | * Example: ``[ 1 2 3 ]`` (notice that there must be a whitespace between the brackets and the first and last element) 251 | 252 | * Indexation: ``@`` 253 | * Example: ``@ 2 [ a b c d e ]`` (it returns the 3rd element of the list, in the example: **c**) 254 | 255 | * Removal: ``~`` 256 | * Example: ``~ 3 [ a b c d e ]`` (it removes the 4th element of the list, in the example: **[ a b c e ]**) 257 | 258 | * Length: ``#`` 259 | * Example: ``# [ a b c ]`` (it returns the length of the list, in the example: **3**) 260 | 261 | * Concatenation: ``+`` 262 | * Example: ``+ z [ x y ]`` (it concatenates the element to the end of the list, in the example: **[ x y z ]**) 263 | 264 | ### Import 265 | A program can import another program located in a file using the ``$`` symbol. For example: 266 | 267 | ``` 268 | $ "libs/math.jan" 269 | $ "utils/vectors.jan" 270 | $ "physics.jan" 271 | ``` 272 | 273 | The path of the files can be expressed as relative (to the current program) or absolute. **This feature is not implemented yet**. 274 | 275 | ### Comments 276 | 277 | The language allows in-line comments using the ``;`` symbol. For example: 278 | 279 | ```common-lisp 280 | even n ; returns true if n is an even number 281 | = 0 % n 2 282 | ``` 283 | 284 | ### Anonymous function 285 | 286 | The language allows to define one (and only one) anonymous function and in case of exist, it will be called after the script is completely parsed. The anonymous function does not have a name or parameters and it must contain one (and only one) expression (non-conditional or complex). For example: 287 | 288 | ```common-lisp 289 | \ + "Result: " compute 10 290 | ``` 291 | 292 | ## Types 293 | 294 | The language has the following data types: 295 | 296 | ### Numbers 297 | 298 | There are two types of numbers: 299 | 300 | _Integers_: whole numbers expressed in base 10, for example: 301 | 302 | ``42`` ``-8`` ``250`` ``0`` ``-67`` 303 | 304 | _Floats_: decimal numbers expressed in base 10, for example: 305 | 306 | ``12.34`` ``-0.001`` ``2.0`` ``99.90`` ``-50.71`` 307 | 308 | Notice that floats should be expressed like this ``0.123`` instead of ``.123`` 309 | 310 | ### Booleans 311 | 312 | Boolean constants are defined as: 313 | 314 | * True: ``.`` (dot) 315 | * False: ``:`` (colon) 316 | 317 | ### Strings 318 | 319 | Strings are immutable sequences of characters and therefore, operations such as _removal_ and _concatenation_ do not affect the given string but return a new one as a consequence of applying the operator. String constants are defined using double quotes, for example: 320 | 321 | ``"First, solve the problem. Then, write the code."`` 322 | 323 | ### Lists 324 | 325 | Lists are fixed-length arrays that can contain zero or more elements. Lists are immutable elements and therefore, operations such as _removal_ and _concatenation_ do not affect the given list but return a new one as a consequence of applying the operator. Lists can contain elements of different types and are defined using the brackets symbols: ``[`` ``]``. For example: 326 | 327 | ``[ 1 2 3 4 5 ]`` 328 | 329 | ## Execution 330 | 331 | ``java -jar jan.jar SCRIPT_PATH`` 332 | 333 | ## Standard Library 334 | 335 | ## Examples 336 | 337 | Here are some sample scripts written in **Jan**: 338 | 339 | ```common-lisp 340 | factorial n 341 | ? = n 0 1 342 | * n factorial - n 1 343 | 344 | \ factorial 5 345 | ``` 346 | 347 | ```common-lisp 348 | fibonacci n 349 | fibo 0 n [ ] 350 | 351 | fibo index limit list 352 | ? >= index limit list 353 | ? = 0 index fibo 1 limit [ 1 ] 354 | ? = 1 index fibo 2 limit [ 1 1 ] 355 | fibo ++ index limit + + @ - index 1 list @ - index 2 list list 356 | 357 | \ fibonacci 10 358 | ``` 359 | 360 | ## License 361 | 362 | The MIT License (MIT) 363 | 364 | Copyright (c) 2015 Mauricio Togneri 365 | 366 | Permission is hereby granted, free of charge, to any person obtaining a copy 367 | of this software and associated documentation files (the "Software"), to deal 368 | in the Software without restriction, including without limitation the rights 369 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 370 | copies of the Software, and to permit persons to whom the Software is 371 | furnished to do so, subject to the following conditions: 372 | 373 | The above copyright notice and this permission notice shall be included in all 374 | copies or substantial portions of the Software. 375 | 376 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 377 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 378 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 379 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 380 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 381 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 382 | SOFTWARE. -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/bytecode/Compiler.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.bytecode; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.tools.DiagnosticCollector; 6 | import javax.tools.JavaCompiler; 7 | import javax.tools.JavaCompiler.CompilationTask; 8 | import javax.tools.JavaFileObject; 9 | import javax.tools.StandardJavaFileManager; 10 | import javax.tools.ToolProvider; 11 | 12 | public class Compiler 13 | { 14 | public static void main(String[] args) 15 | { 16 | // try 17 | // { 18 | // compile("./MyClass.java"); 19 | // } 20 | // catch (IOException e) 21 | // { 22 | // e.printStackTrace(); 23 | // } 24 | } 25 | 26 | private static void compile(String filePath) throws IOException 27 | { 28 | JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 29 | DiagnosticCollector diagnostics = new DiagnosticCollector<>(); 30 | StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); 31 | Iterable compilationUnits = fileManager.getJavaFileObjects(filePath); 32 | CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits); 33 | task.call(); 34 | fileManager.close(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/bytecode/MyClass.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.bytecode; 2 | 3 | import java.util.Arrays; 4 | 5 | public class MyClass 6 | { 7 | public static long factorial(long n) 8 | { 9 | if (n <= 0) 10 | { 11 | return 1; 12 | } 13 | else 14 | { 15 | return n * factorial(n - 1); 16 | } 17 | } 18 | 19 | public static long[] fibonacci(long n) 20 | { 21 | return fibo2(0, n, new long[] {}); 22 | } 23 | 24 | public static long[] fibo2(long index, long limit, long[] list) 25 | { 26 | if (index >= limit) 27 | { 28 | return list; 29 | } 30 | else if (index == 0) 31 | { 32 | return fibo2(1, limit, new long[] {1}); 33 | } 34 | else if (index == 1) 35 | { 36 | return fibo2(2, limit, new long[] {1, 1}); 37 | } 38 | else 39 | { 40 | long value = list[(int) (index - 1)] + list[(int) (index - 2)]; 41 | long[] array = Runtime.$concat(list, value); 42 | 43 | return fibo2(index + 1, limit, array); 44 | } 45 | } 46 | 47 | public static void main(String[] args) 48 | { 49 | System.out.println(Arrays.toString(fibonacci(10))); 50 | } 51 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/bytecode/Runtime.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.bytecode; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.Arrays; 5 | 6 | public class Runtime 7 | { 8 | public static void main(String[] args) throws Exception 9 | { 10 | int[] aaa = new int[] {1, 2, 3}; 11 | 12 | 13 | int[] bbb = $concat(aaa, 4); 14 | System.out.println(Arrays.toString(bbb)); 15 | } 16 | 17 | public static int[] $concat(int[] array, int element) 18 | { 19 | int[] newArray = new int[array.length + 1]; 20 | System.arraycopy(array, 0, newArray, 0, array.length); 21 | newArray[newArray.length - 1] = element; 22 | 23 | return newArray; 24 | } 25 | 26 | public static long[] $concat(long[] array, long element) 27 | { 28 | long[] newArray = new long[array.length + 1]; 29 | System.arraycopy(array, 0, newArray, 0, array.length); 30 | newArray[newArray.length - 1] = element; 31 | 32 | return newArray; 33 | } 34 | 35 | @SuppressWarnings("unchecked") 36 | public static T $concat(T array, E element) 37 | { 38 | E[] newArray = $createArrayAndFill(array, ((E[]) array).length + 1); 39 | newArray[newArray.length - 1] = element; 40 | 41 | return (T) newArray; 42 | } 43 | 44 | @SuppressWarnings("unchecked") 45 | public static T $clone(T object) 46 | { 47 | if (object instanceof int[]) 48 | { 49 | return (T) ((int[]) object).clone(); 50 | } 51 | else if (object instanceof float[]) 52 | { 53 | return (T) ((float[]) object).clone(); 54 | } 55 | else if (object instanceof boolean[]) 56 | { 57 | return (T) ((boolean[]) object).clone(); 58 | } 59 | else if (object instanceof String[]) 60 | { 61 | return (T) ((String[]) object).clone(); 62 | } 63 | else if (object.getClass().isArray()) 64 | { 65 | E[] array = (E[]) object; 66 | 67 | return (T) $createArrayAndFill(array, array.length); 68 | } 69 | else 70 | { 71 | return object; 72 | } 73 | } 74 | 75 | @SuppressWarnings("unchecked") 76 | public static T $createArray(Class clazz, int size) 77 | { 78 | if (clazz.equals(int[].class)) 79 | { 80 | return (T) new int[size]; 81 | } 82 | else if (clazz.equals(float[].class)) 83 | { 84 | return (T) new float[size]; 85 | } 86 | else if (clazz.equals(boolean[].class)) 87 | { 88 | return (T) new boolean[size]; 89 | } 90 | else if (clazz.equals(String[].class)) 91 | { 92 | return (T) new String[size]; 93 | } 94 | else if (clazz.isArray()) 95 | { 96 | return (T) Array.newInstance(clazz.getComponentType(), size); 97 | } 98 | else 99 | { 100 | return null; 101 | } 102 | } 103 | 104 | @SuppressWarnings({"unchecked", "ConstantConditions"}) 105 | private static E[] $createArrayAndFill(T array, int size) 106 | { 107 | E[] source = (E[]) array; 108 | E[] newArray = $createArray(array.getClass(), size); 109 | 110 | for (int i = 0; i < source.length; i++) 111 | { 112 | newArray[i] = $clone(source[i]); 113 | } 114 | 115 | return newArray; 116 | } 117 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/Compiler.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.LexicalAnalyzer; 5 | import com.mauriciotogneri.jan.compiler.lexical.Token; 6 | import com.mauriciotogneri.jan.compiler.semantic.SemanticAnalyzer; 7 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticAnalyzer; 8 | import com.mauriciotogneri.jan.kernel.Function; 9 | import com.mauriciotogneri.jan.kernel.Program; 10 | 11 | public class Compiler 12 | { 13 | public Program compile(String sourcePath) 14 | { 15 | LexicalAnalyzer lexicalAnalyzer = new LexicalAnalyzer(); 16 | List tokens = lexicalAnalyzer.getTokens(sourcePath); 17 | 18 | SyntacticAnalyzer syntacticAnalyzer = new SyntacticAnalyzer(); 19 | Program program = syntacticAnalyzer.getProgram(tokens); 20 | 21 | SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); 22 | semanticAnalyzer.analyze(program); 23 | 24 | return program; 25 | } 26 | 27 | public Function getAnonymousFunction(Program program, String line) 28 | { 29 | char[] characters = line.toCharArray(); 30 | 31 | LexicalAnalyzer lexicalAnalyzer = new LexicalAnalyzer(); 32 | List tokens = lexicalAnalyzer.getTokens(characters); 33 | 34 | SyntacticAnalyzer syntacticAnalyzer = new SyntacticAnalyzer(); 35 | Function function = syntacticAnalyzer.getFunction(tokens); 36 | 37 | function.setTree(program); 38 | 39 | return function; 40 | } 41 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/Character.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 4 | 5 | public enum Character 6 | { 7 | TAB('\t'), // 9 8 | NEW_LINE('\n'), // 10 9 | CARRIAGE_RETURN('\r'), // 13 10 | SPACE(' '), // 32 11 | EXCLAMATION('!'), // 33 12 | DOUBLE_QUOTES('"'), // 34 13 | SHARP('#'), // 35 14 | DOLLAR('$'), // 36 15 | PERCENT('%'), // 37 16 | AMPERSAND('&'), // 38 17 | APOSTROPHE('\''), // 39 18 | OPEN_PARENTHESES('('), // 40 19 | CLOSE_PARENTHESES(')'), // 41 20 | STAR('*'), // 42 21 | PLUS('+'), // 43 22 | COMMA(','), // 44 23 | MINUS('-'), // 45 24 | DOT('.'), // 46 25 | SLASH('/'), // 47 26 | COLON(':'), // 58 27 | SEMICOLON(';'), // 59 28 | LESS('<'), // 60 29 | EQUAL('='), // 61 30 | GREATER('>'), // 62 31 | QUESTION('?'), // 63 32 | AT('@'), // 64 33 | OPEN_BRACKETS('['), // 91 34 | BACK_SLASH('\\'), // 92 35 | CLOSE_BRACKETS(']'), // 93 36 | CARET('^'), // 94 37 | UNDERSCORE('_'), // 95 38 | GRAVE_ACCENT('`'), // 96 39 | OPEN_BRACES('{'), // 123 40 | VERTICAL_BAR('|'), // 124 41 | CLOSE_BRACES('}'), // 125 42 | TILDE('~'), // 126 43 | 44 | NUMBER_0('0'), // 48 45 | NUMBER_1('1'), // 49 46 | NUMBER_2('2'), // 50 47 | NUMBER_3('3'), // 51 48 | NUMBER_4('4'), // 52 49 | NUMBER_5('5'), // 53 50 | NUMBER_6('6'), // 54 51 | NUMBER_7('7'), // 55 52 | NUMBER_8('8'), // 56 53 | NUMBER_9('9'), // 57 54 | 55 | A('A'), // 65 56 | B('B'), // 66 57 | C('C'), // 67 58 | D('D'), // 68 59 | E('E'), // 69 60 | F('F'), // 70 61 | G('G'), // 71 62 | H('H'), // 72 63 | I('I'), // 73 64 | J('J'), // 74 65 | K('K'), // 75 66 | L('L'), // 76 67 | M('M'), // 77 68 | N('N'), // 78 69 | O('O'), // 79 70 | P('P'), // 80 71 | Q('Q'), // 81 72 | R('R'), // 82 73 | S('S'), // 83 74 | T('T'), // 84 75 | U('U'), // 85 76 | V('V'), // 86 77 | W('W'), // 87 78 | X('X'), // 88 79 | Y('Y'), // 89 80 | Z('Z'), // 90 81 | 82 | a('a'), // 97 83 | b('b'), // 98 84 | c('c'), // 99 85 | d('d'), // 100 86 | e('e'), // 101 87 | f('f'), // 102 88 | g('g'), // 103 89 | h('h'), // 104 90 | i('i'), // 105 91 | j('j'), // 106 92 | k('k'), // 107 93 | l('l'), // 108 94 | m('m'), // 109 95 | n('n'), // 110 96 | o('o'), // 111 97 | p('p'), // 112 98 | q('q'), // 113 99 | r('r'), // 114 100 | s('s'), // 115 101 | t('t'), // 116 102 | u('u'), // 117 103 | v('v'), // 118 104 | w('w'), // 119 105 | x('x'), // 120 106 | y('y'), // 121 107 | z('z'); // 122 108 | 109 | private final char character; 110 | 111 | Character(char character) 112 | { 113 | this.character = character; 114 | } 115 | 116 | @Override 117 | public String toString() 118 | { 119 | return String.valueOf(character); 120 | } 121 | 122 | public boolean isNewLine() 123 | { 124 | return (this == CARRIAGE_RETURN) || (this == NEW_LINE); 125 | } 126 | 127 | public boolean isDelimiter() 128 | { 129 | return (this == SPACE) || (this == TAB) || (this == CARRIAGE_RETURN) || (this == NEW_LINE); 130 | } 131 | 132 | public boolean isDigit() 133 | { 134 | return (this == NUMBER_0) || // 135 | (this == NUMBER_1) || // 136 | (this == NUMBER_2) || // 137 | (this == NUMBER_3) || // 138 | (this == NUMBER_4) || // 139 | (this == NUMBER_5) || // 140 | (this == NUMBER_6) || // 141 | (this == NUMBER_7) || // 142 | (this == NUMBER_8) || // 143 | (this == NUMBER_9); 144 | } 145 | 146 | public boolean isLetter() 147 | { 148 | return isLowercaseLetter() || isUppercaseLetter(); 149 | } 150 | 151 | private boolean isUppercaseLetter() 152 | { 153 | return (this == A) || // 154 | (this == B) || // 155 | (this == C) || // 156 | (this == D) || // 157 | (this == E) || // 158 | (this == F) || // 159 | (this == G) || // 160 | (this == H) || // 161 | (this == I) || // 162 | (this == J) || // 163 | (this == K) || // 164 | (this == L) || // 165 | (this == M) || // 166 | (this == N) || // 167 | (this == O) || // 168 | (this == P) || // 169 | (this == Q) || // 170 | (this == R) || // 171 | (this == S) || // 172 | (this == T) || // 173 | (this == U) || // 174 | (this == V) || // 175 | (this == W) || // 176 | (this == X) || // 177 | (this == Y) || // 178 | (this == Z); 179 | } 180 | 181 | private boolean isLowercaseLetter() 182 | { 183 | return (this == a) || // 184 | (this == b) || // 185 | (this == c) || // 186 | (this == d) || // 187 | (this == e) || // 188 | (this == f) || // 189 | (this == g) || // 190 | (this == h) || // 191 | (this == i) || // 192 | (this == j) || // 193 | (this == k) || // 194 | (this == l) || // 195 | (this == m) || // 196 | (this == n) || // 197 | (this == o) || // 198 | (this == p) || // 199 | (this == q) || // 200 | (this == r) || // 201 | (this == s) || // 202 | (this == t) || // 203 | (this == u) || // 204 | (this == v) || // 205 | (this == w) || // 206 | (this == x) || // 207 | (this == y) || // 208 | (this == z); 209 | } 210 | 211 | public Type getDelimiterType() 212 | { 213 | if (this == SPACE) 214 | { 215 | return Type.SPACE; 216 | } 217 | else if (this == TAB) 218 | { 219 | return Type.TAB; 220 | } 221 | else if (this == NEW_LINE) 222 | { 223 | return Type.NEW_LINE; 224 | } 225 | else 226 | { 227 | return null; 228 | } 229 | } 230 | 231 | public Type getOperatorType() 232 | { 233 | if (this == STAR) 234 | { 235 | return Type.ARITHMETIC_MULTIPLICATION; 236 | } 237 | else if (this == SLASH) 238 | { 239 | return Type.ARITHMETIC_DIVISION; 240 | } 241 | else if (this == CARET) 242 | { 243 | return Type.ARITHMETIC_POWER; 244 | } 245 | else if (this == PERCENT) 246 | { 247 | return Type.ARITHMETIC_MODULE; 248 | } 249 | else if (this == EQUAL) 250 | { 251 | return Type.LOGIC_EQUAL; 252 | } 253 | else if (this == AMPERSAND) 254 | { 255 | return Type.LOGIC_AND; 256 | } 257 | else if (this == VERTICAL_BAR) 258 | { 259 | return Type.LOGIC_OR; 260 | } 261 | else if (this == DOLLAR) 262 | { 263 | return Type.IMPORT; 264 | } 265 | else if (this == AT) 266 | { 267 | return Type.ARRAY_INDEX; 268 | } 269 | else if (this == TILDE) 270 | { 271 | return Type.ARRAY_REMOVE; 272 | } 273 | else if (this == SHARP) 274 | { 275 | return Type.ARRAY_LENGTH; 276 | } 277 | else if (this == OPEN_BRACKETS) 278 | { 279 | return Type.LIST_OPEN; 280 | } 281 | else if (this == CLOSE_BRACKETS) 282 | { 283 | return Type.LIST_CLOSE; 284 | } 285 | else if ((this == DOT) || (this == COLON)) 286 | { 287 | return Type.BOOLEAN; 288 | } 289 | else if (this == BACK_SLASH) 290 | { 291 | return Type.ANONYMOUS_FUNCTION; 292 | } 293 | else 294 | { 295 | return null; 296 | } 297 | } 298 | 299 | public String getCharacter() 300 | { 301 | if (this == TAB) 302 | { 303 | return "\\t"; 304 | } 305 | else if (this == CARRIAGE_RETURN) 306 | { 307 | return "\\r"; 308 | } 309 | else if (this == NEW_LINE) 310 | { 311 | return "\\n"; 312 | } 313 | else 314 | { 315 | return toString(); 316 | } 317 | } 318 | 319 | public static Character get(char chr) 320 | { 321 | Character[] characters = Character.values(); 322 | 323 | for (Character character : characters) 324 | { 325 | if (character.character == chr) 326 | { 327 | return character; 328 | } 329 | } 330 | 331 | return null; 332 | } 333 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/LexicalAnalyzer.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.util.List; 8 | 9 | public class LexicalAnalyzer 10 | { 11 | public List getTokens(String sourcePath) 12 | { 13 | char[] characters = getCharacters(sourcePath); 14 | 15 | return getTokens(characters); 16 | } 17 | 18 | public List getTokens(char[] characters) 19 | { 20 | StateMachine stateMachine = new StateMachine(); 21 | 22 | return stateMachine.getTokens(characters); 23 | } 24 | 25 | private char[] getCharacters(String sourcePath) 26 | { 27 | char[] result = null; 28 | BufferedReader bufferedReader = null; 29 | 30 | try 31 | { 32 | bufferedReader = new BufferedReader(new FileReader(sourcePath)); 33 | 34 | File file = new File(sourcePath); 35 | 36 | result = new char[(int) file.length()]; 37 | bufferedReader.read(result); 38 | } 39 | catch (Exception e) 40 | { 41 | throw new RuntimeException("Error reading file: " + sourcePath); 42 | } 43 | finally 44 | { 45 | try 46 | { 47 | if (bufferedReader != null) 48 | { 49 | bufferedReader.close(); 50 | } 51 | } 52 | catch (IOException e) 53 | { 54 | // ignore 55 | } 56 | } 57 | 58 | return result; 59 | } 60 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/LexicalException.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical; 2 | 3 | public class LexicalException extends RuntimeException 4 | { 5 | private static final long serialVersionUID = -1999285208964229934L; 6 | 7 | public LexicalException(Character character, int line, int column) 8 | { 9 | super("Invalid character '" + character.getCharacter() + "' at: [" + line + ", " + column + "]"); 10 | } 11 | 12 | public LexicalException(char character, int line, int column) 13 | { 14 | super("Illegal character '" + character + "' (" + ((int)character) + ") at: [" + line + ", " + column + "]"); 15 | } 16 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/State.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 4 | import com.mauriciotogneri.jan.compiler.lexical.states.InitialState; 5 | 6 | import java.util.List; 7 | 8 | public abstract class State 9 | { 10 | private final int line; 11 | private final int column; 12 | private final StringBuilder lexeme = new StringBuilder(); 13 | private final List tokens; 14 | 15 | protected State(List tokens, int line, int column) 16 | { 17 | this.tokens = tokens; 18 | this.line = line; 19 | this.column = column; 20 | } 21 | 22 | protected int getLine() 23 | { 24 | return line; 25 | } 26 | 27 | protected int getColumn() 28 | { 29 | return column; 30 | } 31 | 32 | protected void addCharacter(Character character) 33 | { 34 | lexeme.append(character.toString()); 35 | } 36 | 37 | protected void setLexeme(String newLexeme) 38 | { 39 | lexeme.setLength(0); 40 | lexeme.append(newLexeme); 41 | } 42 | 43 | protected String getLexeme() 44 | { 45 | return lexeme.toString(); 46 | } 47 | 48 | protected List getTokens() 49 | { 50 | return tokens; 51 | } 52 | 53 | private void addToken(Type type, Character character, int line, int column) 54 | { 55 | tokens.add(new Token(character.toString(), type, line, column)); 56 | } 57 | 58 | protected void addToken(Type type) 59 | { 60 | tokens.add(new Token(getLexeme(), type, line, column)); 61 | } 62 | 63 | protected State createToken(Character character, int line, int column) 64 | { 65 | addToken(character.getDelimiterType(), character, line, column); 66 | 67 | return new InitialState(tokens, line, column); 68 | } 69 | 70 | protected State createToken(Character character, Type type, int line, int column) 71 | { 72 | addToken(type); 73 | addToken(character.getDelimiterType(), character, line, column); 74 | 75 | return new InitialState(tokens, line, column); 76 | } 77 | 78 | public abstract State process(Character character, int line, int column); 79 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/StateMachine.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.states.InitialState; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | class StateMachine 9 | { 10 | private int line = 1; 11 | private int column = 0; 12 | 13 | public List getTokens(char[] characters) 14 | { 15 | List tokens = new ArrayList<>(); 16 | State state = new InitialState(tokens, line, column); 17 | 18 | for (char chr : characters) 19 | { 20 | Character character = Character.get(chr); 21 | 22 | if (character != null) 23 | { 24 | if (character == Character.NEW_LINE) 25 | { 26 | line++; 27 | column = 0; 28 | } 29 | 30 | if (character == Character.TAB) 31 | { 32 | column += 3; 33 | } 34 | 35 | if (!character.isNewLine()) 36 | { 37 | column++; 38 | } 39 | 40 | state = state.process(character, line, column); 41 | } 42 | else 43 | { 44 | throw new LexicalException(chr, line, column); 45 | } 46 | } 47 | 48 | state.process(Character.NEW_LINE, line, column); 49 | 50 | return tokens; 51 | } 52 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/Token.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical; 2 | 3 | public class Token 4 | { 5 | public final String lexeme; 6 | public final Type type; 7 | public final int line; 8 | public final int column; 9 | 10 | public enum Type 11 | { 12 | // general 13 | SYMBOL, // 14 | IMPORT, // 15 | ANONYMOUS_FUNCTION, // 16 | 17 | // delimiters 18 | SPACE, // 19 | TAB, // 20 | NEW_LINE, // 21 | 22 | // literals 23 | INTEGER, // 24 | FLOAT, // 25 | STRING, // 26 | BOOLEAN, // 27 | 28 | // arithmetic 29 | ARITHMETIC_ADD, // 30 | ARITHMETIC_SUBTRACT, // 31 | ARITHMETIC_MULTIPLICATION, // 32 | ARITHMETIC_DIVISION, // 33 | ARITHMETIC_POWER, // 34 | ARITHMETIC_MODULE, // 35 | ARITHMETIC_INCREMENT, // 36 | ARITHMETIC_DECREMENT, // 37 | 38 | // logic 39 | LOGIC_EQUAL, // 40 | LOGIC_NOT_EQUAL, // 41 | LOGIC_GREATER, // 42 | LOGIC_GREATER_EQUAL, // 43 | LOGIC_LESS, // 44 | LOGIC_LESS_EQUAL, // 45 | LOGIC_AND, // 46 | LOGIC_OR, // 47 | LOGIC_NEGATION, // 48 | 49 | // conditional 50 | CONDITIONAL_IF, // 51 | CONDITIONAL_IF_ELSE, // 52 | 53 | // arrays (lists and strings) 54 | ARRAY_INDEX, // 55 | ARRAY_REMOVE, // 56 | ARRAY_LENGTH, // 57 | 58 | // lists 59 | LIST_OPEN, // 60 | LIST_CLOSE; 61 | 62 | public boolean isSeparator() 63 | { 64 | return (this == SPACE) || (this == TAB); 65 | } 66 | 67 | public boolean isLiteral() 68 | { 69 | return (this == INTEGER) || // 70 | (this == FLOAT) || // 71 | (this == STRING) || // 72 | (this == BOOLEAN); 73 | } 74 | 75 | private boolean isArithmeticToken() 76 | { 77 | return (this == ARITHMETIC_ADD) || // 78 | (this == ARITHMETIC_SUBTRACT) || // 79 | (this == ARITHMETIC_MULTIPLICATION) || // 80 | (this == ARITHMETIC_DIVISION) || // 81 | (this == ARITHMETIC_POWER) || // 82 | (this == ARITHMETIC_MODULE) || // 83 | (this == ARITHMETIC_INCREMENT) || // 84 | (this == ARITHMETIC_DECREMENT); 85 | } 86 | 87 | private boolean isLogicToken() 88 | { 89 | return (this == LOGIC_EQUAL) || // 90 | (this == LOGIC_NOT_EQUAL) || // 91 | (this == LOGIC_GREATER) || // 92 | (this == LOGIC_GREATER_EQUAL) || // 93 | (this == LOGIC_LESS) || // 94 | (this == LOGIC_LESS_EQUAL) || // 95 | (this == LOGIC_AND) || // 96 | (this == LOGIC_OR) || // 97 | (this == LOGIC_NEGATION); 98 | } 99 | 100 | private boolean isConditionalToken() 101 | { 102 | return (this == CONDITIONAL_IF) || // 103 | (this == CONDITIONAL_IF_ELSE); 104 | } 105 | 106 | private boolean isArrayToken() 107 | { 108 | return (this == ARRAY_INDEX) || // 109 | (this == ARRAY_REMOVE) || // 110 | (this == ARRAY_LENGTH); 111 | } 112 | 113 | private boolean isListToken() 114 | { 115 | return (this == LIST_OPEN) || // 116 | (this == LIST_CLOSE); 117 | } 118 | 119 | public boolean isPrimitive() 120 | { 121 | return isConditionalToken() || // 122 | isArithmeticToken() || // 123 | isLogicToken() || // 124 | isArrayToken() || // 125 | isListToken(); 126 | } 127 | 128 | public boolean isExpressionToken() 129 | { 130 | return (this == SYMBOL) || // 131 | isConditionalToken() || // 132 | isLiteral() || // 133 | isArithmeticToken() || // 134 | isLogicToken() || // 135 | isArrayToken() || // 136 | isListToken(); 137 | } 138 | } 139 | 140 | public Token(String lexeme, Type type, int line, int column) 141 | { 142 | this.lexeme = lexeme; 143 | this.type = type; 144 | this.line = line; 145 | this.column = column; 146 | } 147 | 148 | @Override 149 | public String toString() 150 | { 151 | return lexeme; 152 | } 153 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/AddState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class AddState extends State 11 | { 12 | public AddState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | addCharacter(Character.PLUS); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character == Character.PLUS) 23 | { 24 | return new IncrementState(getTokens(), line, column); 25 | } 26 | else if (character.isDelimiter()) 27 | { 28 | return createToken(character, Type.ARITHMETIC_ADD, line, column); 29 | } 30 | else 31 | { 32 | throw new LexicalException(character, line, column); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/CommentState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.State; 6 | import com.mauriciotogneri.jan.compiler.lexical.Token; 7 | 8 | public class CommentState extends State 9 | { 10 | public CommentState(List tokens, int line, int column) 11 | { 12 | super(tokens, line, column); 13 | } 14 | 15 | @Override 16 | public State process(Character character, int line, int column) 17 | { 18 | if (character.isNewLine()) 19 | { 20 | return createToken(character, line, column); 21 | } 22 | else 23 | { 24 | return this; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/DecrementState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class DecrementState extends State 11 | { 12 | public DecrementState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | setLexeme(Character.MINUS.toString() + Character.MINUS.toString()); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isDelimiter()) 23 | { 24 | return createToken(character, Type.ARITHMETIC_DECREMENT, line, column); 25 | } 26 | else 27 | { 28 | throw new LexicalException(character, line, column); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/FloatState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class FloatState extends State 11 | { 12 | public FloatState(List tokens, String lexeme, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | setLexeme(lexeme); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isDigit()) 23 | { 24 | addCharacter(character); 25 | 26 | return this; 27 | } 28 | else if (character.isDelimiter()) 29 | { 30 | return createToken(character, Type.FLOAT, line, column); 31 | } 32 | else 33 | { 34 | throw new LexicalException(character, line, column); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/GreaterEqualState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class GreaterEqualState extends State 11 | { 12 | public GreaterEqualState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | setLexeme(Character.GREATER.toString() + Character.EQUAL.toString()); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isDelimiter()) 23 | { 24 | return createToken(character, Type.LOGIC_GREATER_EQUAL, line, column); 25 | } 26 | else 27 | { 28 | throw new LexicalException(character, line, column); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/GreaterState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class GreaterState extends State 11 | { 12 | public GreaterState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | addCharacter(Character.GREATER); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character == Character.EQUAL) 23 | { 24 | return new GreaterEqualState(getTokens(), line, column); 25 | } 26 | else if (character.isDelimiter()) 27 | { 28 | return createToken(character, Type.LOGIC_GREATER, line, column); 29 | } 30 | else 31 | { 32 | throw new LexicalException(character, line, column); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/IfElseState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class IfElseState extends State 11 | { 12 | public IfElseState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | setLexeme(Character.QUESTION.toString() + Character.QUESTION.toString()); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isDelimiter()) 23 | { 24 | return createToken(character, Type.CONDITIONAL_IF_ELSE, line, column); 25 | } 26 | else 27 | { 28 | throw new LexicalException(character, line, column); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/IfState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Character; 4 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 5 | import com.mauriciotogneri.jan.compiler.lexical.State; 6 | import com.mauriciotogneri.jan.compiler.lexical.Token; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 8 | 9 | import java.util.List; 10 | 11 | public class IfState extends State 12 | { 13 | public IfState(List tokens, int line, int column) 14 | { 15 | super(tokens, line, column); 16 | 17 | addCharacter(Character.QUESTION); 18 | } 19 | 20 | @Override 21 | public State process(Character character, int line, int column) 22 | { 23 | if (character == Character.QUESTION) 24 | { 25 | return new IfElseState(getTokens(), line, column); 26 | } 27 | else if (character.isDelimiter()) 28 | { 29 | return createToken(character, Type.CONDITIONAL_IF, line, column); 30 | } 31 | else 32 | { 33 | throw new LexicalException(character, line, column); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/IncrementState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class IncrementState extends State 11 | { 12 | public IncrementState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | setLexeme(Character.PLUS.toString() + Character.PLUS.toString()); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isDelimiter()) 23 | { 24 | return createToken(character, Type.ARITHMETIC_INCREMENT, line, column); 25 | } 26 | else 27 | { 28 | throw new LexicalException(character, line, column); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/InitialState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Character; 4 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 5 | import com.mauriciotogneri.jan.compiler.lexical.State; 6 | import com.mauriciotogneri.jan.compiler.lexical.Token; 7 | 8 | import java.util.List; 9 | 10 | public class InitialState extends State 11 | { 12 | public InitialState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | } 16 | 17 | @Override 18 | public State process(Character character, int line, int column) 19 | { 20 | State state = this; 21 | 22 | if (character.isLetter()) 23 | { 24 | state = new SymbolState(getTokens(), character, line, column); 25 | } 26 | else if (character.isDigit()) 27 | { 28 | state = new IntegerState(getTokens(), character, line, column); 29 | } 30 | else 31 | { 32 | switch (character) 33 | { 34 | case SPACE: 35 | case TAB: 36 | case NEW_LINE: 37 | case CARRIAGE_RETURN: 38 | addCharacter(character); 39 | addToken(character.getDelimiterType()); 40 | break; 41 | 42 | case PLUS: 43 | state = new AddState(getTokens(), line, column); 44 | break; 45 | 46 | case MINUS: 47 | state = new SubtractState(getTokens(), line, column); 48 | break; 49 | 50 | case DOUBLE_QUOTES: 51 | state = new StringState(getTokens(), line, column); 52 | break; 53 | 54 | case EXCLAMATION: 55 | state = new NegationState(getTokens(), line, column); 56 | break; 57 | 58 | case GREATER: 59 | state = new GreaterState(getTokens(), line, column); 60 | break; 61 | 62 | case LESS: 63 | state = new LessState(getTokens(), line, column); 64 | break; 65 | 66 | case QUESTION: 67 | state = new IfState(getTokens(), line, column); 68 | break; 69 | 70 | case SEMICOLON: 71 | state = new CommentState(getTokens(), line, column); 72 | break; 73 | 74 | case STAR: 75 | case SLASH: 76 | case SHARP: 77 | case CARET: 78 | case PERCENT: 79 | case EQUAL: 80 | case AMPERSAND: 81 | case VERTICAL_BAR: 82 | case DOLLAR: 83 | case BACK_SLASH: 84 | case OPEN_BRACKETS: 85 | case CLOSE_BRACKETS: 86 | case AT: 87 | case DOT: 88 | case COLON: 89 | case TILDE: 90 | 91 | // case COMMA: 92 | // case APOSTROPHE: 93 | // case UNDERSCORE: 94 | // case GRAVE_ACCENT: 95 | // case OPEN_PARENTHESES: 96 | // case CLOSE_PARENTHESES: 97 | // case OPEN_BRACES: 98 | // case CLOSE_BRACES: 99 | 100 | state = new OperatorState(getTokens(), character, line, column); 101 | break; 102 | 103 | default: 104 | throw new LexicalException(character, line, column); 105 | } 106 | } 107 | 108 | return state; 109 | } 110 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/IntegerState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class IntegerState extends State 11 | { 12 | public IntegerState(List tokens, Character character, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | addCharacter(character); 17 | } 18 | 19 | public IntegerState(List tokens, String lexeme, int line, int column) 20 | { 21 | super(tokens, line, column); 22 | 23 | setLexeme(lexeme); 24 | } 25 | 26 | @Override 27 | public State process(Character character, int line, int column) 28 | { 29 | if (character.isDigit()) 30 | { 31 | addCharacter(character); 32 | 33 | return this; 34 | } 35 | else if (character == Character.DOT) 36 | { 37 | addCharacter(Character.DOT); 38 | 39 | return new FloatState(getTokens(), getLexeme(), getLine(), getColumn()); 40 | } 41 | else if (character.isDelimiter()) 42 | { 43 | return createToken(character, Type.INTEGER, line, column); 44 | } 45 | else 46 | { 47 | throw new LexicalException(character, line, column); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/LessEqualState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class LessEqualState extends State 11 | { 12 | public LessEqualState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | setLexeme(Character.LESS.toString() + Character.EQUAL.toString()); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isDelimiter()) 23 | { 24 | return createToken(character, Type.LOGIC_LESS_EQUAL, line, column); 25 | } 26 | else 27 | { 28 | throw new LexicalException(character, line, column); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/LessState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class LessState extends State 11 | { 12 | public LessState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | addCharacter(Character.LESS); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character == Character.EQUAL) 23 | { 24 | return new LessEqualState(getTokens(), line, column); 25 | } 26 | else if (character.isDelimiter()) 27 | { 28 | return createToken(character, Type.LOGIC_LESS, line, column); 29 | } 30 | else 31 | { 32 | throw new LexicalException(character, line, column); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/NegationState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class NegationState extends State 11 | { 12 | public NegationState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | addCharacter(Character.EXCLAMATION); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character == Character.EQUAL) 23 | { 24 | return new NotEqualState(getTokens(), line, column); 25 | } 26 | else if (character.isDelimiter()) 27 | { 28 | return createToken(character, Type.LOGIC_NEGATION, line, column); 29 | } 30 | else 31 | { 32 | throw new LexicalException(character, line, column); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/NotEqualState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class NotEqualState extends State 11 | { 12 | public NotEqualState(List tokens, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | setLexeme(Character.EXCLAMATION.toString() + Character.EQUAL.toString()); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isDelimiter()) 23 | { 24 | return createToken(character, Type.LOGIC_NOT_EQUAL, line, column); 25 | } 26 | else 27 | { 28 | throw new LexicalException(character, line, column); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/OperatorState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Character; 4 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 5 | import com.mauriciotogneri.jan.compiler.lexical.State; 6 | import com.mauriciotogneri.jan.compiler.lexical.Token; 7 | 8 | import java.util.List; 9 | 10 | public class OperatorState extends State 11 | { 12 | public OperatorState(List tokens, Character character, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | addCharacter(character); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isDelimiter()) 23 | { 24 | Character operatorCharacter = Character.get(getLexeme().charAt(0)); 25 | 26 | if (operatorCharacter != null) 27 | { 28 | return createToken(character, operatorCharacter.getOperatorType(), line, column); 29 | } 30 | else 31 | { 32 | throw new LexicalException(character, line, column); 33 | } 34 | } 35 | else 36 | { 37 | throw new LexicalException(character, line, column); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/StringEndState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class StringEndState extends State 11 | { 12 | public StringEndState(List tokens, String lexeme, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | setLexeme(lexeme); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isDelimiter()) 23 | { 24 | return createToken(character, Type.STRING, line, column); 25 | } 26 | else 27 | { 28 | throw new LexicalException(character, line, column); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/StringEscapeState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | 9 | public class StringEscapeState extends State 10 | { 11 | public StringEscapeState(List tokens, String lexeme, int line, int column) 12 | { 13 | super(tokens, line, column); 14 | 15 | setLexeme(lexeme); 16 | } 17 | 18 | @Override 19 | public State process(Character character, int line, int column) 20 | { 21 | if ((character == Character.NEW_LINE) || (character == Character.CARRIAGE_RETURN)) 22 | { 23 | throw new LexicalException(character, line, column); 24 | } 25 | else 26 | { 27 | addCharacter(character); 28 | 29 | return new StringState(getTokens(), getLexeme(), line, column); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/StringState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | 9 | public class StringState extends State 10 | { 11 | public StringState(List tokens, int line, int column) 12 | { 13 | super(tokens, line, column); 14 | } 15 | 16 | public StringState(List tokens, String lexeme, int line, int column) 17 | { 18 | super(tokens, line, column); 19 | 20 | setLexeme(lexeme); 21 | } 22 | 23 | @Override 24 | public State process(Character character, int line, int column) 25 | { 26 | if (character == Character.DOUBLE_QUOTES) 27 | { 28 | return new StringEndState(getTokens(), getLexeme(), line, column); 29 | } 30 | else if (character == Character.BACK_SLASH) 31 | { 32 | addCharacter(character); 33 | 34 | return new StringEscapeState(getTokens(), getLexeme(), line, column); 35 | } 36 | else if (character.isNewLine()) 37 | { 38 | throw new LexicalException(character, line, column); 39 | } 40 | else 41 | { 42 | addCharacter(character); 43 | 44 | return this; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/SubtractState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Character; 4 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 5 | import com.mauriciotogneri.jan.compiler.lexical.State; 6 | import com.mauriciotogneri.jan.compiler.lexical.Token; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 8 | 9 | import java.util.List; 10 | 11 | public class SubtractState extends State 12 | { 13 | public SubtractState(List tokens, int line, int column) 14 | { 15 | super(tokens, line, column); 16 | 17 | addCharacter(Character.MINUS); 18 | } 19 | 20 | @Override 21 | public State process(Character character, int line, int column) 22 | { 23 | if (character == Character.MINUS) 24 | { 25 | return new DecrementState(getTokens(), line, column); 26 | } 27 | else if (character.isDigit()) 28 | { 29 | addCharacter(character); 30 | 31 | return new IntegerState(getTokens(), getLexeme(), line, column); 32 | } 33 | else if (character.isDelimiter()) 34 | { 35 | return createToken(character, Type.ARITHMETIC_SUBTRACT, line, column); 36 | } 37 | else 38 | { 39 | throw new LexicalException(character, line, column); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/lexical/states/SymbolState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.lexical.states; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Character; 5 | import com.mauriciotogneri.jan.compiler.lexical.LexicalException; 6 | import com.mauriciotogneri.jan.compiler.lexical.State; 7 | import com.mauriciotogneri.jan.compiler.lexical.Token; 8 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 9 | 10 | public class SymbolState extends State 11 | { 12 | public SymbolState(List tokens, Character character, int line, int column) 13 | { 14 | super(tokens, line, column); 15 | 16 | addCharacter(character); 17 | } 18 | 19 | @Override 20 | public State process(Character character, int line, int column) 21 | { 22 | if (character.isLetter() || character.isDigit() || (character == Character.UNDERSCORE)) 23 | { 24 | addCharacter(character); 25 | 26 | return this; 27 | } 28 | else if (character.isDelimiter()) 29 | { 30 | return createToken(character, Type.SYMBOL, line, column); 31 | } 32 | else 33 | { 34 | throw new LexicalException(character, line, column); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/semantic/SemanticAnalyzer.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.semantic; 2 | 3 | import com.mauriciotogneri.jan.kernel.Program; 4 | 5 | public class SemanticAnalyzer 6 | { 7 | public void analyze(Program program) 8 | { 9 | program.analyzeTree(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/semantic/SemanticException.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.semantic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | 5 | public class SemanticException extends RuntimeException 6 | { 7 | private static final long serialVersionUID = 8235362518654985229L; 8 | 9 | public SemanticException(String message, Token token) 10 | { 11 | super(message + " '" + token + "' at: [" + token.line + ", " + token.column + "]"); 12 | } 13 | 14 | public SemanticException(String message) 15 | { 16 | super(message); 17 | } 18 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/State.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Function; 5 | import com.mauriciotogneri.jan.kernel.Program; 6 | 7 | public abstract class State 8 | { 9 | private final Program program; 10 | 11 | protected State(Program program) 12 | { 13 | this.program = program; 14 | } 15 | 16 | protected Program getProgram() 17 | { 18 | return program; 19 | } 20 | 21 | protected void addImport(String path) 22 | { 23 | program.addImport(path); 24 | } 25 | 26 | protected void addFunction(Function function) 27 | { 28 | if (function.isEmpty()) 29 | { 30 | throw new SyntacticException("Function is empty", function.getName()); 31 | } 32 | 33 | if (containsFunction(function)) 34 | { 35 | throw new SyntacticException("Function '" + function.getName().lexeme + "' already defined", function.getName().line, function.getName().column); 36 | } 37 | 38 | program.addFunction(function); 39 | } 40 | 41 | private boolean containsFunction(Function function) 42 | { 43 | return program.containsFunction(function.getName().lexeme); 44 | } 45 | 46 | public abstract State process(Token token); 47 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/StateMachine.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.states.AnonymousExpressionStartState; 6 | import com.mauriciotogneri.jan.compiler.syntactic.states.InitialState; 7 | import com.mauriciotogneri.jan.kernel.Expression; 8 | import com.mauriciotogneri.jan.kernel.Function; 9 | import com.mauriciotogneri.jan.kernel.Program; 10 | 11 | import java.util.List; 12 | 13 | class StateMachine 14 | { 15 | public Program getProgram(List tokens) 16 | { 17 | Program program = new Program(); 18 | 19 | State state = new InitialState(program); 20 | 21 | for (Token token : tokens) 22 | { 23 | state = state.process(token); 24 | } 25 | 26 | return program; 27 | } 28 | 29 | public Function getAnonymousFunction(List tokens) 30 | { 31 | Program program = new Program(); 32 | Function function = new Function(new Token("", Type.ANONYMOUS_FUNCTION, 1, 1)); 33 | Expression expression = new Expression(); 34 | 35 | State state = new AnonymousExpressionStartState(program, function, expression); 36 | 37 | for (Token token : tokens) 38 | { 39 | state = state.process(token); 40 | } 41 | 42 | return function; 43 | } 44 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/SyntacticAnalyzer.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic; 2 | 3 | import java.util.List; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Function; 6 | import com.mauriciotogneri.jan.kernel.Program; 7 | 8 | public class SyntacticAnalyzer 9 | { 10 | public Program getProgram(List tokens) 11 | { 12 | StateMachine stateMachine = new StateMachine(); 13 | 14 | return stateMachine.getProgram(tokens); 15 | } 16 | 17 | public Function getFunction(List tokens) 18 | { 19 | StateMachine stateMachine = new StateMachine(); 20 | 21 | return stateMachine.getAnonymousFunction(tokens); 22 | } 23 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/SyntacticException.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | 5 | public class SyntacticException extends RuntimeException 6 | { 7 | private static final long serialVersionUID = -4336303078381836231L; 8 | 9 | public SyntacticException(String message, Token token) 10 | { 11 | super(message + " '" + token + "' at: [" + token.line + ", " + token.column + "]"); 12 | } 13 | 14 | public SyntacticException(String message, int line, int column) 15 | { 16 | super(message + " at: [" + line + ", " + column + "]"); 17 | } 18 | 19 | public SyntacticException(Token token) 20 | { 21 | super("Invalid token '" + token + "' at: [" + token.line + ", " + token.column + "]"); 22 | } 23 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/AnonymousExpressionEndState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Expression; 8 | import com.mauriciotogneri.jan.kernel.Function; 9 | import com.mauriciotogneri.jan.kernel.Program; 10 | 11 | public class AnonymousExpressionEndState extends State 12 | { 13 | private final Function function; 14 | private final Expression expression; 15 | 16 | public AnonymousExpressionEndState(Program program, Function function, Expression expression) 17 | { 18 | super(program); 19 | 20 | this.function = function; 21 | this.expression = expression; 22 | } 23 | 24 | @Override 25 | public State process(Token token) 26 | { 27 | if (token.type.isSeparator()) 28 | { 29 | return new AnonymousExpressionStartState(getProgram(), function, expression); 30 | } 31 | else if (token.type == Type.NEW_LINE) 32 | { 33 | function.addExpression(expression); 34 | addFunction(function); 35 | 36 | return new InitialState(getProgram()); 37 | } 38 | else 39 | { 40 | throw new SyntacticException(token); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/AnonymousExpressionStartState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Expression; 8 | import com.mauriciotogneri.jan.kernel.Function; 9 | import com.mauriciotogneri.jan.kernel.Program; 10 | 11 | public class AnonymousExpressionStartState extends State 12 | { 13 | private final Function function; 14 | private final Expression expression; 15 | 16 | public AnonymousExpressionStartState(Program program, Function function, Expression expression) 17 | { 18 | super(program); 19 | 20 | this.function = function; 21 | this.expression = expression; 22 | } 23 | 24 | @Override 25 | public State process(Token token) 26 | { 27 | if (token.type.isSeparator()) 28 | { 29 | return this; 30 | } 31 | else if (token.type.isExpressionToken()) 32 | { 33 | expression.addElement(token); 34 | 35 | return new AnonymousExpressionEndState(getProgram(), function, expression); 36 | } 37 | else if (token.type == Type.NEW_LINE) 38 | { 39 | if (expression.isEmpty()) 40 | { 41 | throw new SyntacticException("Anonymous function is empty", token); 42 | } 43 | 44 | function.addExpression(expression); 45 | addFunction(function); 46 | 47 | return new InitialState(getProgram()); 48 | } 49 | else 50 | { 51 | throw new SyntacticException(token); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/AnonymousFunctionState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.syntactic.State; 5 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 6 | import com.mauriciotogneri.jan.kernel.Expression; 7 | import com.mauriciotogneri.jan.kernel.Function; 8 | import com.mauriciotogneri.jan.kernel.Program; 9 | 10 | public class AnonymousFunctionState extends State 11 | { 12 | private final Function function; 13 | 14 | public AnonymousFunctionState(Program program, Function function) 15 | { 16 | super(program); 17 | 18 | this.function = function; 19 | } 20 | 21 | @Override 22 | public State process(Token token) 23 | { 24 | if (token.type.isSeparator()) 25 | { 26 | return new AnonymousExpressionStartState(getProgram(), function, new Expression()); 27 | } 28 | else 29 | { 30 | throw new SyntacticException(token); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/ExpressionEndState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Expression; 8 | import com.mauriciotogneri.jan.kernel.Function; 9 | import com.mauriciotogneri.jan.kernel.Program; 10 | 11 | public class ExpressionEndState extends State 12 | { 13 | private final Function function; 14 | private final Expression expression; 15 | 16 | public ExpressionEndState(Program program, Function function, Expression expression) 17 | { 18 | super(program); 19 | 20 | this.function = function; 21 | this.expression = expression; 22 | } 23 | 24 | @Override 25 | public State process(Token token) 26 | { 27 | if (token.type.isSeparator()) 28 | { 29 | return new ExpressionStartState(getProgram(), function, expression); 30 | } 31 | else if (token.type == Type.NEW_LINE) 32 | { 33 | function.addExpression(expression); 34 | 35 | return new FunctionDefinedState(getProgram(), function); 36 | } 37 | else 38 | { 39 | throw new SyntacticException(token); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/ExpressionStartState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Expression; 8 | import com.mauriciotogneri.jan.kernel.Function; 9 | import com.mauriciotogneri.jan.kernel.Program; 10 | 11 | public class ExpressionStartState extends State 12 | { 13 | private final Function function; 14 | private final Expression expression; 15 | 16 | public ExpressionStartState(Program program, Function function, Expression expression) 17 | { 18 | super(program); 19 | 20 | this.function = function; 21 | this.expression = expression; 22 | } 23 | 24 | @Override 25 | public State process(Token token) 26 | { 27 | if (token.type.isSeparator()) 28 | { 29 | return this; 30 | } 31 | else if (token.type.isExpressionToken()) 32 | { 33 | expression.addElement(token); 34 | 35 | return new ExpressionEndState(getProgram(), function, expression); 36 | } 37 | else if (token.type == Type.NEW_LINE) 38 | { 39 | if (!expression.isEmpty()) 40 | { 41 | function.addExpression(expression); 42 | } 43 | 44 | return new FunctionDefinedState(getProgram(), function); 45 | } 46 | else 47 | { 48 | throw new SyntacticException(token); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/FunctionDefinedState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Expression; 8 | import com.mauriciotogneri.jan.kernel.Function; 9 | import com.mauriciotogneri.jan.kernel.Program; 10 | 11 | public class FunctionDefinedState extends State 12 | { 13 | private final Function function; 14 | 15 | public FunctionDefinedState(Program program, Function function) 16 | { 17 | super(program); 18 | 19 | this.function = function; 20 | } 21 | 22 | @Override 23 | public State process(Token token) 24 | { 25 | if (token.type == Type.TAB) 26 | { 27 | return new ExpressionStartState(getProgram(), function, new Expression()); 28 | } 29 | else if (token.type == Type.SYMBOL) 30 | { 31 | addFunction(function); 32 | 33 | return new FunctionDefinitionState(getProgram(), new Function(token)); 34 | } 35 | else if (token.type == Type.NEW_LINE) 36 | { 37 | addFunction(function); 38 | 39 | return new InitialState(getProgram()); 40 | } 41 | else 42 | { 43 | throw new SyntacticException(token); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/FunctionDefinitionState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Function; 8 | import com.mauriciotogneri.jan.kernel.Program; 9 | 10 | public class FunctionDefinitionState extends State 11 | { 12 | private final Function function; 13 | 14 | public FunctionDefinitionState(Program program, Function function) 15 | { 16 | super(program); 17 | 18 | this.function = function; 19 | } 20 | 21 | @Override 22 | public State process(Token token) 23 | { 24 | if (token.type.isSeparator()) 25 | { 26 | return new FunctionParameterStartState(getProgram(), function); 27 | } 28 | else if (token.type == Type.NEW_LINE) 29 | { 30 | return new FunctionDefinedState(getProgram(), function); 31 | } 32 | else 33 | { 34 | throw new SyntacticException(token); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/FunctionParameterEndState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Function; 8 | import com.mauriciotogneri.jan.kernel.Program; 9 | 10 | public class FunctionParameterEndState extends State 11 | { 12 | private final Function function; 13 | 14 | public FunctionParameterEndState(Program program, Function function) 15 | { 16 | super(program); 17 | 18 | this.function = function; 19 | } 20 | 21 | @Override 22 | public State process(Token token) 23 | { 24 | if (token.type.isSeparator()) 25 | { 26 | return new FunctionParameterStartState(getProgram(), function); 27 | } 28 | else if (token.type == Type.NEW_LINE) 29 | { 30 | return new FunctionDefinedState(getProgram(), function); 31 | } 32 | else 33 | { 34 | throw new SyntacticException(token); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/FunctionParameterStartState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Function; 8 | import com.mauriciotogneri.jan.kernel.Program; 9 | 10 | public class FunctionParameterStartState extends State 11 | { 12 | private final Function function; 13 | 14 | public FunctionParameterStartState(Program program, Function function) 15 | { 16 | super(program); 17 | 18 | this.function = function; 19 | } 20 | 21 | @Override 22 | public State process(Token token) 23 | { 24 | if (token.type.isSeparator()) 25 | { 26 | return this; 27 | } 28 | else if (token.type == Type.NEW_LINE) 29 | { 30 | return new FunctionDefinedState(getProgram(), function); 31 | } 32 | else if (token.type == Type.SYMBOL) 33 | { 34 | function.addParameter(token.lexeme); 35 | 36 | return new FunctionParameterEndState(getProgram(), function); 37 | } 38 | else 39 | { 40 | throw new SyntacticException(token); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/ImportEndState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Program; 8 | 9 | public class ImportEndState extends State 10 | { 11 | private final String path; 12 | 13 | public ImportEndState(Program program, String path) 14 | { 15 | super(program); 16 | 17 | this.path = path; 18 | } 19 | 20 | @Override 21 | public State process(Token token) 22 | { 23 | if (token.type == Type.NEW_LINE) 24 | { 25 | addImport(path); 26 | 27 | return new InitialState(getProgram()); 28 | } 29 | else 30 | { 31 | throw new SyntacticException(token); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/ImportStartState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Program; 8 | 9 | public class ImportStartState extends State 10 | { 11 | public ImportStartState(Program program) 12 | { 13 | super(program); 14 | } 15 | 16 | @Override 17 | public State process(Token token) 18 | { 19 | if (token.type.isSeparator()) 20 | { 21 | return this; 22 | } 23 | else if (token.type == Type.STRING) 24 | { 25 | return new ImportEndState(getProgram(), token.lexeme); 26 | } 27 | else 28 | { 29 | throw new SyntacticException(token); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/ImportState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.syntactic.State; 5 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 6 | import com.mauriciotogneri.jan.kernel.Program; 7 | 8 | public class ImportState extends State 9 | { 10 | public ImportState(Program program) 11 | { 12 | super(program); 13 | } 14 | 15 | @Override 16 | public State process(Token token) 17 | { 18 | if (token.type.isSeparator()) 19 | { 20 | return new ImportStartState(getProgram()); 21 | } 22 | else 23 | { 24 | throw new SyntacticException(token); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/compiler/syntactic/states/InitialState.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.compiler.syntactic.states; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.syntactic.State; 6 | import com.mauriciotogneri.jan.compiler.syntactic.SyntacticException; 7 | import com.mauriciotogneri.jan.kernel.Function; 8 | import com.mauriciotogneri.jan.kernel.Program; 9 | 10 | public class InitialState extends State 11 | { 12 | public InitialState(Program program) 13 | { 14 | super(program); 15 | } 16 | 17 | @Override 18 | public State process(Token token) 19 | { 20 | if (token.type == Type.NEW_LINE) 21 | { 22 | return this; 23 | } 24 | else if (token.type == Type.IMPORT) 25 | { 26 | return new ImportState(getProgram()); 27 | } 28 | else if (token.type == Type.SYMBOL) 29 | { 30 | return new FunctionDefinitionState(getProgram(), new Function(token)); 31 | } 32 | else if (token.type == Type.ANONYMOUS_FUNCTION) 33 | { 34 | return new AnonymousFunctionState(getProgram(), new Function(token)); 35 | } 36 | else 37 | { 38 | throw new SyntacticException(token); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/execution/input/DefaultProgramInput.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.execution.input; 2 | 3 | import java.util.Scanner; 4 | 5 | public class DefaultProgramInput implements ProgramInput 6 | { 7 | private static final String PROMPT = "> "; 8 | 9 | private final Scanner scanner = new Scanner(System.in); 10 | 11 | @Override 12 | public String getExpression() 13 | { 14 | System.out.print("\n\n" + PROMPT); 15 | 16 | return scanner.nextLine(); 17 | } 18 | 19 | @Override 20 | public void close() 21 | { 22 | scanner.close(); 23 | } 24 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/execution/input/ProgramInput.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.execution.input; 2 | 3 | public interface ProgramInput 4 | { 5 | String getExpression(); 6 | 7 | void close(); 8 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/execution/output/DefaultProgramOutput.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.execution.output; 2 | 3 | import com.mauriciotogneri.jan.kernel.Value; 4 | 5 | public class DefaultProgramOutput implements ProgramOutput 6 | { 7 | @Override 8 | public void processResult(Value result) 9 | { 10 | System.out.print(result.toString()); 11 | } 12 | 13 | @Override 14 | public void processError(String text) 15 | { 16 | System.err.print(text); 17 | } 18 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/execution/output/ProgramOutput.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.execution.output; 2 | 3 | import com.mauriciotogneri.jan.kernel.Value; 4 | 5 | public interface ProgramOutput 6 | { 7 | void processResult(Value result); 8 | 9 | void processError(String text); 10 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/Context.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel; 2 | 3 | 4 | public class Context 5 | { 6 | private final Value[] values; 7 | 8 | public Context(Value... values) 9 | { 10 | this.values = values; 11 | } 12 | 13 | public Context() 14 | { 15 | this(new Value[0]); 16 | } 17 | 18 | public Value get(int index) 19 | { 20 | return values[index]; 21 | } 22 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/Expression.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.compiler.semantic.SemanticException; 6 | import com.mauriciotogneri.jan.kernel.nodes.FunctionNode; 7 | import com.mauriciotogneri.jan.kernel.nodes.ListNode; 8 | import com.mauriciotogneri.jan.kernel.nodes.LiteralNode; 9 | import com.mauriciotogneri.jan.kernel.nodes.OperatorNode; 10 | import com.mauriciotogneri.jan.kernel.nodes.ParameterNode; 11 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 12 | import com.mauriciotogneri.jan.kernel.nodes.conditional.IfNode; 13 | import com.mauriciotogneri.jan.kernel.nodes.list.ListCloseNode; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Stack; 18 | 19 | public class Expression 20 | { 21 | private final List elements = new ArrayList<>(); 22 | private Node root; 23 | 24 | public void addElement(Token token) 25 | { 26 | elements.add(0, token); 27 | } 28 | 29 | public boolean isEmpty() 30 | { 31 | return elements.isEmpty(); 32 | } 33 | 34 | public boolean setTree(Parameters parameters, Program program) 35 | { 36 | Stack stack = new Stack<>(); 37 | 38 | for (Token token : elements) 39 | { 40 | if (token.type.isLiteral()) 41 | { 42 | LiteralNode node = new LiteralNode(token); 43 | stack.push(node); 44 | } 45 | else if (token.type == Type.SYMBOL) 46 | { 47 | if (parameters.containsParameter(token.lexeme)) 48 | { 49 | ParameterNode node = new ParameterNode(token, parameters.getIndex(token.lexeme)); 50 | stack.push(node); 51 | } 52 | else if (program.containsFunction(token.lexeme)) 53 | { 54 | Function function = program.getFunction(token.lexeme); 55 | 56 | if (function != null) 57 | { 58 | FunctionNode node = new FunctionNode(token, function); 59 | 60 | applyOperator(token, node, stack); 61 | } 62 | else 63 | { 64 | throw new SemanticException("Function not defined", token); 65 | } 66 | } 67 | else 68 | { 69 | throw new SemanticException("Symbol not defined", token); 70 | } 71 | } 72 | else if (token.type.isPrimitive()) 73 | { 74 | PrimitiveNode node = PrimitiveNode.get(token); 75 | 76 | if (node != null) 77 | { 78 | if (token.type == Type.LIST_CLOSE) 79 | { 80 | stack.push(node); 81 | } 82 | else if (token.type == Type.LIST_OPEN) 83 | { 84 | List list = new ArrayList<>(); 85 | 86 | ListNode listNode = null; 87 | 88 | while (!stack.isEmpty()) 89 | { 90 | Node operand = stack.pop(); 91 | 92 | if (operand instanceof ListCloseNode) 93 | { 94 | listNode = new ListNode(token, list); 95 | break; 96 | } 97 | else 98 | { 99 | list.add(operand); 100 | } 101 | } 102 | 103 | if (listNode != null) 104 | { 105 | stack.push(listNode); 106 | } 107 | else 108 | { 109 | throw new SemanticException("List close not found", token); 110 | } 111 | } 112 | else 113 | { 114 | applyOperator(token, node, stack); 115 | } 116 | } 117 | else 118 | { 119 | throw new SemanticException("Token not valid", token); 120 | } 121 | } 122 | else 123 | { 124 | throw new SemanticException("Token not valid", token); 125 | } 126 | } 127 | 128 | if (stack.size() == 1) 129 | { 130 | Node node = stack.pop(); 131 | 132 | if (node instanceof ListCloseNode) 133 | { 134 | throw new SemanticException("Invalid list definition", elements.get(0)); 135 | } 136 | else 137 | { 138 | root = node; 139 | } 140 | } 141 | else 142 | { 143 | throw new SemanticException("Invalid expression. It should return only one value", elements.get(0)); 144 | } 145 | 146 | return (root instanceof IfNode); 147 | } 148 | 149 | private void applyOperator(Token token, OperatorNode node, Stack stack) 150 | { 151 | for (int i = 0; i < node.numberOfOperands; i++) 152 | { 153 | if (!stack.isEmpty()) 154 | { 155 | Node operand = stack.pop(); 156 | node.addChild(operand); 157 | } 158 | else 159 | { 160 | throw new SemanticException("Insufficient operands to apply primitive", token); 161 | } 162 | } 163 | 164 | stack.push(node); 165 | } 166 | 167 | public Value evaluate(Context context) 168 | { 169 | return root.evaluate(context); 170 | } 171 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/Function.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.semantic.SemanticException; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class Function 10 | { 11 | private final Token name; 12 | private final Parameters parameters = new Parameters(); 13 | private final List expressions = new ArrayList<>(); 14 | 15 | public Function(Token name) 16 | { 17 | this.name = name; 18 | } 19 | 20 | public Token getName() 21 | { 22 | return name; 23 | } 24 | 25 | public int getNumberOfParameters() 26 | { 27 | return parameters.getSize(); 28 | } 29 | 30 | public void setTree(Program program) 31 | { 32 | for (int i = 0; i < expressions.size(); i++) 33 | { 34 | Expression expression = expressions.get(i); 35 | 36 | boolean isLastExpression = (i == (expressions.size() - 1)); 37 | boolean conditional = expression.setTree(parameters, program); 38 | 39 | if (isLastExpression == conditional) 40 | { 41 | throw new SemanticException("Function '" + name.lexeme + "' must end with a non conditional expression"); 42 | } 43 | } 44 | } 45 | 46 | public boolean isEmpty() 47 | { 48 | return expressions.isEmpty(); 49 | } 50 | 51 | public void addParameter(String name) 52 | { 53 | parameters.add(name); 54 | } 55 | 56 | public void addExpression(Expression expression) 57 | { 58 | expressions.add(expression); 59 | } 60 | 61 | public Value evaluate(Context context) 62 | { 63 | for (Expression expression : expressions) 64 | { 65 | Value result = expression.evaluate(context); 66 | 67 | if (result != null) 68 | { 69 | return result; 70 | } 71 | } 72 | 73 | throw new RuntimeException("Function '" + name.lexeme + "' didn't return any value"); 74 | } 75 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/Jan.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel; 2 | 3 | import com.mauriciotogneri.jan.compiler.Compiler; 4 | import com.mauriciotogneri.jan.execution.input.DefaultProgramInput; 5 | import com.mauriciotogneri.jan.execution.input.ProgramInput; 6 | import com.mauriciotogneri.jan.execution.output.DefaultProgramOutput; 7 | import com.mauriciotogneri.jan.execution.output.ProgramOutput; 8 | 9 | public class Jan 10 | { 11 | public void run(String sourcePath, ProgramOutput programOutput, ProgramInput programInput) 12 | { 13 | try 14 | { 15 | Compiler compiler = new Compiler(); 16 | Program program = compiler.compile(sourcePath); 17 | 18 | if (program.hasEntryPoint()) 19 | { 20 | // long start = System.nanoTime(); 21 | 22 | Value result = program.run(); 23 | programOutput.processResult(result); 24 | 25 | // long end = System.nanoTime(); 26 | 27 | // System.out.println(((end - start) / 1000) + " us"); 28 | } 29 | 30 | if (programInput != null) 31 | { 32 | String line; 33 | 34 | do 35 | { 36 | line = programInput.getExpression(); 37 | 38 | if ((line != null) && (!line.isEmpty())) 39 | { 40 | try 41 | { 42 | Function function = compiler.getAnonymousFunction(program, line); 43 | Value result = program.evaluate(function); 44 | programOutput.processResult(result); 45 | } 46 | catch (Exception e) 47 | { 48 | printException(e, programOutput); 49 | } 50 | } 51 | } while ((line != null) && (!line.isEmpty())); 52 | 53 | programInput.close(); 54 | } 55 | } 56 | catch (Exception e) 57 | { 58 | printException(e, programOutput); 59 | } 60 | } 61 | 62 | public void run(String sourcePath, ProgramOutput programOutput) 63 | { 64 | run(sourcePath, programOutput, null); 65 | } 66 | 67 | private void printException(Exception e, ProgramOutput programOutput) 68 | { 69 | programOutput.processError(e.getClass().getSimpleName() + ": " + e.getMessage()); 70 | } 71 | 72 | public static void main(String[] args) 73 | { 74 | if (args.length > 0) 75 | { 76 | Jan jan = new Jan(); 77 | 78 | ProgramOutput programOutput = new DefaultProgramOutput(); 79 | 80 | boolean showPrompt = (args.length <= 1) || Boolean.parseBoolean(args[1]); 81 | 82 | if (showPrompt) 83 | { 84 | ProgramInput programInput = new DefaultProgramInput(); 85 | 86 | jan.run(args[0], programOutput, programInput); 87 | } 88 | else 89 | { 90 | jan.run(args[0], programOutput); 91 | } 92 | } 93 | else 94 | { 95 | System.err.println("Usage: java -jar jan.jar [SOURCE_PATH] [SHOW_PROMPT]"); 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/Node.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public abstract class Node 9 | { 10 | protected final Token token; 11 | private final List children = new ArrayList<>(); 12 | 13 | protected Node(Token token) 14 | { 15 | this.token = token; 16 | } 17 | 18 | public void addChild(Node node) 19 | { 20 | children.add(node); 21 | } 22 | 23 | protected Value get(int index, Context context) 24 | { 25 | Node node = children.get(index); 26 | 27 | return node.evaluate(context); 28 | } 29 | 30 | protected Context getContext(Context context) 31 | { 32 | Value[] values = new Value[children.size()]; 33 | 34 | for (int i = 0; i < children.size(); i++) 35 | { 36 | Node node = children.get(i); 37 | 38 | values[i] = node.evaluate(context); 39 | } 40 | 41 | return new Context(values); 42 | } 43 | 44 | public abstract Value evaluate(Context context); 45 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/Parameters.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | class Parameters 7 | { 8 | private int index = 0; 9 | private final Map parameters = new HashMap<>(); 10 | 11 | public void add(String name) 12 | { 13 | parameters.put(name, index++); 14 | } 15 | 16 | public int getSize() 17 | { 18 | return parameters.size(); 19 | } 20 | 21 | public boolean containsParameter(String name) 22 | { 23 | return parameters.containsKey(name); 24 | } 25 | 26 | public int getIndex(String name) 27 | { 28 | Integer result = parameters.get(name); 29 | 30 | return (result != null) ? result : -1; 31 | } 32 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/Program.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel; 2 | 3 | import com.mauriciotogneri.jan.kernel.Value.Type; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | public class Program 12 | { 13 | private Type returnType; 14 | private final List imports = new ArrayList<>(); 15 | private final Map functions = new HashMap<>(); 16 | 17 | public void addImport(String path) 18 | { 19 | imports.add(path); 20 | } 21 | 22 | public Type getReturnType() 23 | { 24 | return returnType; 25 | } 26 | 27 | private void setTree() 28 | { 29 | Collection list = functions.values(); 30 | 31 | for (Function function : list) 32 | { 33 | function.setTree(this); 34 | } 35 | } 36 | 37 | public void analyzeTree() 38 | { 39 | setTree(); 40 | 41 | // TODO 42 | 43 | returnType = Type.UNDEFINED; 44 | } 45 | 46 | public void addFunction(Function function) 47 | { 48 | functions.put(function.getName().lexeme, function); 49 | } 50 | 51 | public boolean containsFunction(String name) 52 | { 53 | return functions.containsKey(name); 54 | } 55 | 56 | public Function getFunction(String name) 57 | { 58 | return functions.get(name); 59 | } 60 | 61 | public Value evaluate(Function function) 62 | { 63 | Context context = new Context(); 64 | 65 | return function.evaluate(context); 66 | } 67 | 68 | public Value run() 69 | { 70 | return evaluate(functions.get("\\")); 71 | } 72 | 73 | public boolean hasEntryPoint() 74 | { 75 | return functions.containsKey("\\"); 76 | } 77 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/Value.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.List; 5 | 6 | public class Value 7 | { 8 | private final Type type; 9 | private final Object value; 10 | 11 | public enum Type 12 | { 13 | NUMBER, BOOLEAN, STRING, LIST, UNDEFINED 14 | } 15 | 16 | private Value(Type type, Object value) 17 | { 18 | this.type = type; 19 | this.value = value; 20 | } 21 | 22 | public static Value asNumber(BigDecimal value) 23 | { 24 | return new Value(Type.NUMBER, value); 25 | } 26 | 27 | public static Value asString(String value) 28 | { 29 | return new Value(Type.STRING, value); 30 | } 31 | 32 | public static Value asBoolean(Boolean value) 33 | { 34 | return new Value(Type.BOOLEAN, value); 35 | } 36 | 37 | public static Value asList(List value) 38 | { 39 | return new Value(Type.LIST, value); 40 | } 41 | 42 | public boolean isNumber() 43 | { 44 | return type == Type.NUMBER; 45 | } 46 | 47 | public boolean isBoolean() 48 | { 49 | return type == Type.BOOLEAN; 50 | } 51 | 52 | public boolean isString() 53 | { 54 | return type == Type.STRING; 55 | } 56 | 57 | public boolean isList() 58 | { 59 | return type == Type.LIST; 60 | } 61 | 62 | public BigDecimal getNumber() 63 | { 64 | return (BigDecimal) value; 65 | } 66 | 67 | public boolean getBoolean() 68 | { 69 | return (Boolean) value; 70 | } 71 | 72 | public String getString() 73 | { 74 | return (String) value; 75 | } 76 | 77 | @SuppressWarnings("unchecked") 78 | public List getList() 79 | { 80 | return (List) value; 81 | } 82 | 83 | @Override 84 | public String toString() 85 | { 86 | StringBuilder builder = new StringBuilder(); 87 | printResult(this, builder); 88 | 89 | return builder.toString(); 90 | } 91 | 92 | private void printResult(Value value, StringBuilder builder) 93 | { 94 | if (value.isNumber()) 95 | { 96 | builder.append(value.getNumber()); 97 | } 98 | else if (value.isBoolean()) 99 | { 100 | builder.append(value.getBoolean()); 101 | } 102 | else if (value.isString()) 103 | { 104 | builder.append("\""); 105 | builder.append(value.getString()); 106 | builder.append("\""); 107 | } 108 | else if (value.isList()) 109 | { 110 | List list = value.getList(); 111 | 112 | builder.append("["); 113 | 114 | for (int i = 0; i < list.size(); i++) 115 | { 116 | Value element = list.get(i); 117 | 118 | if (i != 0) 119 | { 120 | builder.append(", "); 121 | } 122 | 123 | printResult(element, builder); 124 | } 125 | 126 | builder.append("]"); 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/FunctionNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Function; 6 | import com.mauriciotogneri.jan.kernel.Value; 7 | 8 | public class FunctionNode extends OperatorNode 9 | { 10 | private final Function function; 11 | 12 | public FunctionNode(Token token, Function function) 13 | { 14 | super(token, function.getNumberOfParameters()); 15 | 16 | this.function = function; 17 | } 18 | 19 | @Override 20 | public Value evaluate(Context context) 21 | { 22 | return function.evaluate(getContext(context)); 23 | } 24 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/ListNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Node; 6 | import com.mauriciotogneri.jan.kernel.Value; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class ListNode extends Node 12 | { 13 | private final List list; 14 | 15 | public ListNode(Token token, List list) 16 | { 17 | super(token); 18 | 19 | this.list = list; 20 | } 21 | 22 | @Override 23 | public Value evaluate(Context context) 24 | { 25 | List result = new ArrayList<>(); 26 | 27 | for (Node node : list) 28 | { 29 | result.add(node.evaluate(context)); 30 | } 31 | 32 | return Value.asList(result); 33 | } 34 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/LiteralNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Node; 6 | import com.mauriciotogneri.jan.kernel.Value; 7 | 8 | import java.math.BigDecimal; 9 | 10 | public class LiteralNode extends Node 11 | { 12 | private final Value value; 13 | 14 | public LiteralNode(Token token) 15 | { 16 | super(token); 17 | 18 | if ((token.type == Token.Type.INTEGER) || (token.type == Token.Type.FLOAT)) 19 | { 20 | this.value = Value.asNumber(new BigDecimal(token.lexeme)); 21 | } 22 | else if (token.type == Token.Type.STRING) 23 | { 24 | this.value = Value.asString(token.lexeme); 25 | } 26 | else if (token.type == Token.Type.BOOLEAN) 27 | { 28 | this.value = Value.asBoolean(token.lexeme.equals(".")); 29 | } 30 | else 31 | { 32 | this.value = null; 33 | } 34 | } 35 | 36 | @Override 37 | public Value evaluate(Context context) 38 | { 39 | return value; 40 | } 41 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/OperatorNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Node; 5 | 6 | public abstract class OperatorNode extends Node 7 | { 8 | public final int numberOfOperands; 9 | 10 | OperatorNode(Token token, int numberOfOperands) 11 | { 12 | super(token); 13 | 14 | this.numberOfOperands = numberOfOperands; 15 | } 16 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/ParameterNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Node; 6 | import com.mauriciotogneri.jan.kernel.Value; 7 | 8 | public class ParameterNode extends Node 9 | { 10 | private final int index; 11 | 12 | public ParameterNode(Token token, int index) 13 | { 14 | super(token); 15 | 16 | this.index = index; 17 | } 18 | 19 | @Override 20 | public Value evaluate(Context context) 21 | { 22 | return context.get(index); 23 | } 24 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/PrimitiveNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token.Type; 5 | import com.mauriciotogneri.jan.kernel.nodes.arithmetic.AddNode; 6 | import com.mauriciotogneri.jan.kernel.nodes.arithmetic.DecrementNode; 7 | import com.mauriciotogneri.jan.kernel.nodes.arithmetic.DivisionNode; 8 | import com.mauriciotogneri.jan.kernel.nodes.arithmetic.IncrementNode; 9 | import com.mauriciotogneri.jan.kernel.nodes.arithmetic.ModuleNode; 10 | import com.mauriciotogneri.jan.kernel.nodes.arithmetic.MultiplicationNode; 11 | import com.mauriciotogneri.jan.kernel.nodes.arithmetic.PowerNode; 12 | import com.mauriciotogneri.jan.kernel.nodes.arithmetic.SubtractNode; 13 | import com.mauriciotogneri.jan.kernel.nodes.array.IndexNode; 14 | import com.mauriciotogneri.jan.kernel.nodes.array.LengthNode; 15 | import com.mauriciotogneri.jan.kernel.nodes.array.RemoveNode; 16 | import com.mauriciotogneri.jan.kernel.nodes.conditional.IfElseNode; 17 | import com.mauriciotogneri.jan.kernel.nodes.conditional.IfNode; 18 | import com.mauriciotogneri.jan.kernel.nodes.list.ListCloseNode; 19 | import com.mauriciotogneri.jan.kernel.nodes.list.ListOpenNode; 20 | import com.mauriciotogneri.jan.kernel.nodes.logic.AndNode; 21 | import com.mauriciotogneri.jan.kernel.nodes.logic.EqualNode; 22 | import com.mauriciotogneri.jan.kernel.nodes.logic.GreaterEqualNode; 23 | import com.mauriciotogneri.jan.kernel.nodes.logic.GreaterNode; 24 | import com.mauriciotogneri.jan.kernel.nodes.logic.LessEqualNode; 25 | import com.mauriciotogneri.jan.kernel.nodes.logic.LessNode; 26 | import com.mauriciotogneri.jan.kernel.nodes.logic.NegationNode; 27 | import com.mauriciotogneri.jan.kernel.nodes.logic.NotEqualNode; 28 | import com.mauriciotogneri.jan.kernel.nodes.logic.OrNode; 29 | 30 | public abstract class PrimitiveNode extends OperatorNode 31 | { 32 | protected PrimitiveNode(Token token, int numberOfOperands) 33 | { 34 | super(token, numberOfOperands); 35 | } 36 | 37 | public static PrimitiveNode get(Token token) 38 | { 39 | if (token.type == Type.ARITHMETIC_ADD) 40 | { 41 | return new AddNode(token); 42 | } 43 | else if (token.type == Type.ARITHMETIC_SUBTRACT) 44 | { 45 | return new SubtractNode(token); 46 | } 47 | else if (token.type == Type.ARITHMETIC_MULTIPLICATION) 48 | { 49 | return new MultiplicationNode(token); 50 | } 51 | else if (token.type == Type.ARITHMETIC_DIVISION) 52 | { 53 | return new DivisionNode(token); 54 | } 55 | else if (token.type == Type.ARITHMETIC_POWER) 56 | { 57 | return new PowerNode(token); 58 | } 59 | else if (token.type == Type.ARITHMETIC_MODULE) 60 | { 61 | return new ModuleNode(token); 62 | } 63 | else if (token.type == Type.ARITHMETIC_INCREMENT) 64 | { 65 | return new IncrementNode(token); 66 | } 67 | else if (token.type == Type.ARITHMETIC_DECREMENT) 68 | { 69 | return new DecrementNode(token); 70 | } 71 | else if (token.type == Type.LOGIC_EQUAL) 72 | { 73 | return new EqualNode(token); 74 | } 75 | else if (token.type == Type.LOGIC_NOT_EQUAL) 76 | { 77 | return new NotEqualNode(token); 78 | } 79 | else if (token.type == Type.LOGIC_GREATER) 80 | { 81 | return new GreaterNode(token); 82 | } 83 | else if (token.type == Type.LOGIC_GREATER_EQUAL) 84 | { 85 | return new GreaterEqualNode(token); 86 | } 87 | else if (token.type == Type.LOGIC_LESS) 88 | { 89 | return new LessNode(token); 90 | } 91 | else if (token.type == Type.LOGIC_LESS_EQUAL) 92 | { 93 | return new LessEqualNode(token); 94 | } 95 | else if (token.type == Type.LOGIC_AND) 96 | { 97 | return new AndNode(token); 98 | } 99 | else if (token.type == Type.LOGIC_OR) 100 | { 101 | return new OrNode(token); 102 | } 103 | else if (token.type == Type.LOGIC_NEGATION) 104 | { 105 | return new NegationNode(token); 106 | } 107 | else if (token.type == Type.CONDITIONAL_IF) 108 | { 109 | return new IfNode(token); 110 | } 111 | else if (token.type == Type.CONDITIONAL_IF_ELSE) 112 | { 113 | return new IfElseNode(token); 114 | } 115 | else if (token.type == Type.ARRAY_INDEX) 116 | { 117 | return new IndexNode(token); 118 | } 119 | else if (token.type == Type.ARRAY_REMOVE) 120 | { 121 | return new RemoveNode(token); 122 | } 123 | else if (token.type == Type.ARRAY_LENGTH) 124 | { 125 | return new LengthNode(token); 126 | } 127 | else if (token.type == Type.LIST_OPEN) 128 | { 129 | return new ListOpenNode(token); 130 | } 131 | else if (token.type == Type.LIST_CLOSE) 132 | { 133 | return new ListCloseNode(token); 134 | } 135 | 136 | return null; 137 | } 138 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/arithmetic/AddNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.arithmetic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | import java.math.BigDecimal; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class AddNode extends PrimitiveNode 13 | { 14 | public AddNode(Token token) 15 | { 16 | super(token, 2); 17 | } 18 | 19 | @Override 20 | public Value evaluate(Context context) 21 | { 22 | Value operand1 = get(0, context); 23 | Value operand2 = get(1, context); 24 | 25 | if (operand1.isNumber() && operand2.isNumber()) 26 | { 27 | BigDecimal value1 = operand1.getNumber(); 28 | BigDecimal value2 = operand2.getNumber(); 29 | 30 | return Value.asNumber(value1.add(value2)); 31 | } 32 | else if (operand1.isString() && operand2.isString()) 33 | { 34 | String value1 = operand1.getString(); 35 | String value2 = operand2.getString(); 36 | 37 | return Value.asString(value1 + value2); 38 | } 39 | else if (operand1.isList() && operand2.isList()) 40 | { 41 | List value1 = operand1.getList(); 42 | List value2 = operand2.getList(); 43 | 44 | List result = new ArrayList<>(); 45 | result.addAll(value1); 46 | result.addAll(value2); 47 | 48 | return Value.asList(result); 49 | } 50 | else if (operand1.isNumber() && operand2.isList()) 51 | { 52 | BigDecimal value1 = operand1.getNumber(); 53 | List value2 = operand2.getList(); 54 | 55 | List result = new ArrayList<>(); 56 | result.addAll(value2); 57 | result.add(Value.asNumber(value1)); 58 | 59 | return Value.asList(result); 60 | } 61 | else if (operand1.isBoolean() && operand2.isList()) 62 | { 63 | Boolean value1 = operand1.getBoolean(); 64 | List value2 = operand2.getList(); 65 | 66 | List result = new ArrayList<>(); 67 | result.addAll(value2); 68 | result.add(Value.asBoolean(value1)); 69 | 70 | return Value.asList(result); 71 | } 72 | else if (operand1.isString() && operand2.isList()) 73 | { 74 | String value1 = operand1.getString(); 75 | List value2 = operand2.getList(); 76 | 77 | List result = new ArrayList<>(); 78 | result.addAll(value2); 79 | result.add(Value.asString(value1)); 80 | 81 | return Value.asList(result); 82 | } 83 | 84 | // TODO: explain more 85 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 86 | } 87 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/arithmetic/DecrementNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.arithmetic; 2 | 3 | import java.math.BigDecimal; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.operations.UnaryNumericNode; 7 | 8 | public class DecrementNode extends UnaryNumericNode 9 | { 10 | public DecrementNode(Token token) 11 | { 12 | super(token); 13 | } 14 | 15 | @Override 16 | public Value evaluate(BigDecimal operand) 17 | { 18 | return Value.asNumber(operand.subtract(BigDecimal.ONE)); 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/arithmetic/DivisionNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.arithmetic; 2 | 3 | import java.math.BigDecimal; 4 | import java.math.RoundingMode; 5 | import com.mauriciotogneri.jan.compiler.lexical.Token; 6 | import com.mauriciotogneri.jan.kernel.Value; 7 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNumericNode; 8 | 9 | public class DivisionNode extends BinaryNumericNode 10 | { 11 | public DivisionNode(Token token) 12 | { 13 | super(token); 14 | } 15 | 16 | @Override 17 | public Value evaluate(BigDecimal operand1, BigDecimal operand2) 18 | { 19 | BigDecimal result = operand1.divide(operand2, 10, RoundingMode.HALF_EVEN); 20 | 21 | try 22 | { 23 | return Value.asNumber(BigDecimal.valueOf(result.intValueExact())); 24 | } 25 | catch (Exception e) 26 | { 27 | return Value.asNumber(result); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/arithmetic/IncrementNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.arithmetic; 2 | 3 | import java.math.BigDecimal; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.operations.UnaryNumericNode; 7 | 8 | public class IncrementNode extends UnaryNumericNode 9 | { 10 | public IncrementNode(Token token) 11 | { 12 | super(token); 13 | } 14 | 15 | @Override 16 | public Value evaluate(BigDecimal operand) 17 | { 18 | return Value.asNumber(operand.add(BigDecimal.ONE)); 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/arithmetic/ModuleNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.arithmetic; 2 | 3 | import java.math.BigDecimal; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNumericNode; 7 | 8 | public class ModuleNode extends BinaryNumericNode 9 | { 10 | public ModuleNode(Token token) 11 | { 12 | super(token); 13 | } 14 | 15 | @Override 16 | public Value evaluate(BigDecimal operand1, BigDecimal operand2) 17 | { 18 | return Value.asNumber(operand1.remainder(operand2)); 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/arithmetic/MultiplicationNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.arithmetic; 2 | 3 | import java.math.BigDecimal; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNumericNode; 7 | 8 | public class MultiplicationNode extends BinaryNumericNode 9 | { 10 | public MultiplicationNode(Token token) 11 | { 12 | super(token); 13 | } 14 | 15 | @Override 16 | public Value evaluate(BigDecimal operand1, BigDecimal operand2) 17 | { 18 | return Value.asNumber(operand1.multiply(operand2)); 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/arithmetic/PowerNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.arithmetic; 2 | 3 | import java.math.BigDecimal; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNumericNode; 7 | 8 | public class PowerNode extends BinaryNumericNode 9 | { 10 | public PowerNode(Token token) 11 | { 12 | super(token); 13 | } 14 | 15 | @Override 16 | public Value evaluate(BigDecimal operand1, BigDecimal operand2) 17 | { 18 | return Value.asNumber(operand1.pow(operand2.intValue())); 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/arithmetic/SubtractNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.arithmetic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Value; 5 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNumericNode; 6 | 7 | import java.math.BigDecimal; 8 | 9 | public class SubtractNode extends BinaryNumericNode 10 | { 11 | public SubtractNode(Token token) 12 | { 13 | super(token); 14 | } 15 | 16 | @Override 17 | public Value evaluate(BigDecimal operand1, BigDecimal operand2) 18 | { 19 | return Value.asNumber(operand1.subtract(operand2)); 20 | } 21 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/array/IndexNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.array; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | import java.math.BigDecimal; 9 | import java.util.List; 10 | 11 | public class IndexNode extends PrimitiveNode 12 | { 13 | public IndexNode(Token token) 14 | { 15 | super(token, 2); 16 | } 17 | 18 | @Override 19 | public Value evaluate(Context context) 20 | { 21 | Value operand1 = get(0, context); 22 | Value operand2 = get(1, context); 23 | 24 | if (operand1.isNumber() && operand2.isList()) 25 | { 26 | BigDecimal value1 = operand1.getNumber(); 27 | List value2 = operand2.getList(); 28 | 29 | return value2.get(value1.intValue()); 30 | } 31 | else if (operand1.isNumber() && operand2.isString()) 32 | { 33 | BigDecimal value1 = operand1.getNumber(); 34 | String value2 = operand2.getString(); 35 | 36 | return Value.asString(String.valueOf(value2.charAt(value1.intValue()))); 37 | } 38 | 39 | // TODO: explain more 40 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 41 | } 42 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/array/LengthNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.array; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | import java.math.BigDecimal; 9 | import java.util.List; 10 | 11 | public class LengthNode extends PrimitiveNode 12 | { 13 | public LengthNode(Token token) 14 | { 15 | super(token, 1); 16 | } 17 | 18 | @Override 19 | public Value evaluate(Context context) 20 | { 21 | Value operand = get(0, context); 22 | 23 | if (operand.isList()) 24 | { 25 | List value = operand.getList(); 26 | 27 | return Value.asNumber(BigDecimal.valueOf(value.size())); 28 | } 29 | else if (operand.isString()) 30 | { 31 | String value = operand.getString(); 32 | 33 | return Value.asNumber(BigDecimal.valueOf(value.length())); 34 | } 35 | 36 | // TODO: explain more 37 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 38 | } 39 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/array/RemoveNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.array; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | import java.math.BigDecimal; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class RemoveNode extends PrimitiveNode 13 | { 14 | public RemoveNode(Token token) 15 | { 16 | super(token, 2); 17 | } 18 | 19 | @Override 20 | public Value evaluate(Context context) 21 | { 22 | Value operand1 = get(0, context); 23 | Value operand2 = get(1, context); 24 | 25 | if (operand1.isNumber() && operand2.isList()) 26 | { 27 | BigDecimal value1 = operand1.getNumber(); 28 | List value2 = operand2.getList(); 29 | 30 | List result = new ArrayList<>(); 31 | result.addAll(value2); 32 | result.remove(value1.intValue()); 33 | 34 | return Value.asList(result); 35 | } 36 | else if (operand1.isNumber() && operand2.isString()) 37 | { 38 | BigDecimal value1 = operand1.getNumber(); 39 | String value2 = operand2.getString(); 40 | 41 | String result = value2.substring(0, value1.intValue()) + value2.substring(value1.intValue() + 1); 42 | 43 | return Value.asString(result); 44 | } 45 | 46 | // TODO: explain more 47 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 48 | } 49 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/conditional/IfElseNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.conditional; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | public class IfElseNode extends PrimitiveNode 9 | { 10 | public IfElseNode(Token token) 11 | { 12 | super(token, 3); 13 | } 14 | 15 | @Override 16 | public Value evaluate(Context context) 17 | { 18 | Value operand1 = get(0, context); 19 | 20 | if (operand1.isBoolean()) 21 | { 22 | if (operand1.getBoolean()) 23 | { 24 | return get(1, context); 25 | } 26 | else 27 | { 28 | return get(2, context); 29 | } 30 | } 31 | 32 | // TODO: explain more 33 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 34 | } 35 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/conditional/IfNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.conditional; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | public class IfNode extends PrimitiveNode 9 | { 10 | public IfNode(Token token) 11 | { 12 | super(token, 2); 13 | } 14 | 15 | @Override 16 | public Value evaluate(Context context) 17 | { 18 | Value operand1 = get(0, context); 19 | 20 | if (operand1.isBoolean()) 21 | { 22 | if (operand1.getBoolean()) 23 | { 24 | return get(1, context); 25 | } 26 | else 27 | { 28 | return null; 29 | } 30 | } 31 | 32 | // TODO: explain more 33 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 34 | } 35 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/list/ListCloseNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.list; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | public class ListCloseNode extends PrimitiveNode 9 | { 10 | public ListCloseNode(Token token) 11 | { 12 | super(token, 0); 13 | } 14 | 15 | @Override 16 | public Value evaluate(Context context) 17 | { 18 | return null; 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/list/ListOpenNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.list; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | public class ListOpenNode extends PrimitiveNode 9 | { 10 | public ListOpenNode(Token token) 11 | { 12 | super(token, 0); 13 | } 14 | 15 | @Override 16 | public Value evaluate(Context context) 17 | { 18 | return null; 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/logic/AndNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.logic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Value; 5 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryBooleanNode; 6 | 7 | public class AndNode extends BinaryBooleanNode 8 | { 9 | public AndNode(Token token) 10 | { 11 | super(token); 12 | } 13 | 14 | @Override 15 | protected Value evaluate(Boolean operand1, Boolean operand2) 16 | { 17 | return Value.asBoolean(operand1 && operand2); 18 | } 19 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/logic/EqualNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.logic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Value; 5 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNode; 6 | 7 | import java.math.BigDecimal; 8 | import java.util.List; 9 | 10 | public class EqualNode extends BinaryNode 11 | { 12 | public EqualNode(Token token) 13 | { 14 | super(token); 15 | } 16 | 17 | @Override 18 | protected boolean evaluate(BigDecimal operand1, BigDecimal operand2) 19 | { 20 | return equalNumbers(operand1, operand2); 21 | } 22 | 23 | @Override 24 | protected boolean evaluate(Boolean operand1, Boolean operand2) 25 | { 26 | return equalBooleans(operand1, operand2); 27 | } 28 | 29 | @Override 30 | protected boolean evaluate(String operand1, String operand2) 31 | { 32 | return equalStrings(operand1, operand2); 33 | } 34 | 35 | @Override 36 | protected boolean evaluate(List operand1, List operand2) 37 | { 38 | return equalLists(operand1, operand2); 39 | } 40 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/logic/GreaterEqualNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.logic; 2 | 3 | import java.math.BigDecimal; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNumericNode; 7 | 8 | public class GreaterEqualNode extends BinaryNumericNode 9 | { 10 | public GreaterEqualNode(Token token) 11 | { 12 | super(token); 13 | } 14 | 15 | @Override 16 | protected Value evaluate(BigDecimal operand1, BigDecimal operand2) 17 | { 18 | return Value.asBoolean(operand1.compareTo(operand2) >= 0); 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/logic/GreaterNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.logic; 2 | 3 | import java.math.BigDecimal; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNumericNode; 7 | 8 | public class GreaterNode extends BinaryNumericNode 9 | { 10 | public GreaterNode(Token token) 11 | { 12 | super(token); 13 | } 14 | 15 | @Override 16 | protected Value evaluate(BigDecimal operand1, BigDecimal operand2) 17 | { 18 | return Value.asBoolean(operand1.compareTo(operand2) > 0); 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/logic/LessEqualNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.logic; 2 | 3 | import java.math.BigDecimal; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNumericNode; 7 | 8 | public class LessEqualNode extends BinaryNumericNode 9 | { 10 | public LessEqualNode(Token token) 11 | { 12 | super(token); 13 | } 14 | 15 | @Override 16 | protected Value evaluate(BigDecimal operand1, BigDecimal operand2) 17 | { 18 | return Value.asBoolean(operand1.compareTo(operand2) <= 0); 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/logic/LessNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.logic; 2 | 3 | import java.math.BigDecimal; 4 | import com.mauriciotogneri.jan.compiler.lexical.Token; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNumericNode; 7 | 8 | public class LessNode extends BinaryNumericNode 9 | { 10 | public LessNode(Token token) 11 | { 12 | super(token); 13 | } 14 | 15 | @Override 16 | protected Value evaluate(BigDecimal operand1, BigDecimal operand2) 17 | { 18 | return Value.asBoolean(operand1.compareTo(operand2) < 0); 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/logic/NegationNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.logic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Value; 5 | import com.mauriciotogneri.jan.kernel.nodes.operations.UnaryBooleanNode; 6 | 7 | public class NegationNode extends UnaryBooleanNode 8 | { 9 | public NegationNode(Token token) 10 | { 11 | super(token); 12 | } 13 | 14 | @Override 15 | protected Value evaluate(Boolean operand) 16 | { 17 | return Value.asBoolean(!operand); 18 | } 19 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/logic/NotEqualNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.logic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Value; 5 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryNode; 6 | 7 | import java.math.BigDecimal; 8 | import java.util.List; 9 | 10 | public class NotEqualNode extends BinaryNode 11 | { 12 | public NotEqualNode(Token token) 13 | { 14 | super(token); 15 | } 16 | 17 | @Override 18 | protected boolean evaluate(BigDecimal operand1, BigDecimal operand2) 19 | { 20 | return !equalNumbers(operand1, operand2); 21 | } 22 | 23 | @Override 24 | protected boolean evaluate(Boolean operand1, Boolean operand2) 25 | { 26 | return !equalBooleans(operand1, operand2); 27 | } 28 | 29 | @Override 30 | protected boolean evaluate(String operand1, String operand2) 31 | { 32 | return !equalStrings(operand1, operand2); 33 | } 34 | 35 | @Override 36 | protected boolean evaluate(List operand1, List operand2) 37 | { 38 | return !equalLists(operand1, operand2); 39 | } 40 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/logic/OrNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.logic; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Value; 5 | import com.mauriciotogneri.jan.kernel.nodes.operations.BinaryBooleanNode; 6 | 7 | public class OrNode extends BinaryBooleanNode 8 | { 9 | public OrNode(Token token) 10 | { 11 | super(token); 12 | } 13 | 14 | @Override 15 | protected Value evaluate(Boolean operand1, Boolean operand2) 16 | { 17 | return Value.asBoolean(operand1 || operand2); 18 | } 19 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/operations/BinaryBooleanNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.operations; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | public abstract class BinaryBooleanNode extends PrimitiveNode 9 | { 10 | protected BinaryBooleanNode(Token token) 11 | { 12 | super(token, 2); 13 | } 14 | 15 | @Override 16 | public Value evaluate(Context context) 17 | { 18 | Value operand1 = get(0, context); 19 | Value operand2 = get(1, context); 20 | 21 | if (operand1.isBoolean() && operand2.isBoolean()) 22 | { 23 | Boolean value1 = operand1.getBoolean(); 24 | Boolean value2 = operand2.getBoolean(); 25 | 26 | return evaluate(value1, value2); 27 | } 28 | 29 | // TODO: explain more 30 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 31 | } 32 | 33 | protected abstract Value evaluate(Boolean operand1, Boolean operand2); 34 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/operations/BinaryNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.operations; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | import java.math.BigDecimal; 9 | import java.util.List; 10 | 11 | public abstract class BinaryNode extends PrimitiveNode 12 | { 13 | protected BinaryNode(Token token) 14 | { 15 | super(token, 2); 16 | } 17 | 18 | @Override 19 | public Value evaluate(Context context) 20 | { 21 | Value operand1 = get(0, context); 22 | Value operand2 = get(1, context); 23 | 24 | if (operand1.isBoolean() && operand2.isBoolean()) 25 | { 26 | Boolean value1 = operand1.getBoolean(); 27 | Boolean value2 = operand2.getBoolean(); 28 | 29 | return Value.asBoolean(evaluate(value1, value2)); 30 | } 31 | else if (operand1.isNumber() && operand2.isNumber()) 32 | { 33 | BigDecimal value1 = operand1.getNumber(); 34 | BigDecimal value2 = operand2.getNumber(); 35 | 36 | return Value.asBoolean(evaluate(value1, value2)); 37 | } 38 | else if (operand1.isString() && operand2.isString()) 39 | { 40 | String value1 = operand1.getString(); 41 | String value2 = operand2.getString(); 42 | 43 | return Value.asBoolean(evaluate(value1, value2)); 44 | } 45 | else if (operand1.isList() && operand2.isList()) 46 | { 47 | List value1 = operand1.getList(); 48 | List value2 = operand2.getList(); 49 | 50 | return Value.asBoolean(evaluate(value1, value2)); 51 | } 52 | 53 | // TODO: explain more 54 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 55 | } 56 | 57 | protected boolean equalNumbers(BigDecimal operand1, BigDecimal operand2) 58 | { 59 | return (operand1.compareTo(operand2) == 0); 60 | } 61 | 62 | protected boolean equalBooleans(Boolean operand1, Boolean operand2) 63 | { 64 | return (operand1.booleanValue() == operand2.booleanValue()); 65 | } 66 | 67 | protected boolean equalStrings(String operand1, String operand2) 68 | { 69 | return (operand1.equals(operand2)); 70 | } 71 | 72 | protected boolean equalLists(List operand1, List operand2) 73 | { 74 | if (operand1.size() == operand2.size()) 75 | { 76 | for (int i = 0; i < operand1.size(); i++) 77 | { 78 | Value value1 = operand1.get(i); 79 | Value value2 = operand2.get(i); 80 | 81 | if (!equalValues(value1, value2)) 82 | { 83 | return false; 84 | } 85 | } 86 | 87 | return true; 88 | } 89 | else 90 | { 91 | return false; 92 | } 93 | } 94 | 95 | private boolean equalValues(Value operand1, Value operand2) 96 | { 97 | if (operand1.isNumber() && operand2.isNumber()) 98 | { 99 | BigDecimal value1 = operand1.getNumber(); 100 | BigDecimal value2 = operand2.getNumber(); 101 | 102 | return evaluate(value1, value2); 103 | } 104 | else if (operand1.isBoolean() && operand2.isBoolean()) 105 | { 106 | Boolean value1 = operand1.getBoolean(); 107 | Boolean value2 = operand2.getBoolean(); 108 | 109 | return evaluate(value1, value2); 110 | } 111 | else if (operand1.isString() && operand2.isString()) 112 | { 113 | String value1 = operand1.getString(); 114 | String value2 = operand2.getString(); 115 | 116 | return evaluate(value1, value2); 117 | } 118 | else if (operand1.isList() && operand2.isList()) 119 | { 120 | List value1 = operand1.getList(); 121 | List value2 = operand2.getList(); 122 | 123 | return evaluate(value1, value2); 124 | } 125 | else 126 | { 127 | return false; 128 | } 129 | } 130 | 131 | protected abstract boolean evaluate(BigDecimal operand1, BigDecimal operand2); 132 | 133 | protected abstract boolean evaluate(Boolean operand1, Boolean operand2); 134 | 135 | protected abstract boolean evaluate(String operand1, String operand2); 136 | 137 | protected abstract boolean evaluate(List operand1, List operand2); 138 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/operations/BinaryNumericNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.operations; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | import java.math.BigDecimal; 9 | 10 | public abstract class BinaryNumericNode extends PrimitiveNode 11 | { 12 | protected BinaryNumericNode(Token token) 13 | { 14 | super(token, 2); 15 | } 16 | 17 | @Override 18 | public Value evaluate(Context context) 19 | { 20 | Value operand1 = get(0, context); 21 | Value operand2 = get(1, context); 22 | 23 | if (operand1.isNumber() && operand2.isNumber()) 24 | { 25 | BigDecimal value1 = operand1.getNumber(); 26 | BigDecimal value2 = operand2.getNumber(); 27 | 28 | return evaluate(value1, value2); 29 | } 30 | 31 | // TODO: explain more 32 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 33 | } 34 | 35 | protected abstract Value evaluate(BigDecimal operand1, BigDecimal operand2); 36 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/operations/UnaryBooleanNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.operations; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | public abstract class UnaryBooleanNode extends PrimitiveNode 9 | { 10 | protected UnaryBooleanNode(Token token) 11 | { 12 | super(token, 1); 13 | } 14 | 15 | @Override 16 | public Value evaluate(Context context) 17 | { 18 | Value operand = get(0, context); 19 | 20 | if (operand.isBoolean()) 21 | { 22 | Boolean value = operand.getBoolean(); 23 | 24 | return evaluate(value); 25 | } 26 | 27 | // TODO: explain more 28 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 29 | } 30 | 31 | protected abstract Value evaluate(Boolean operand); 32 | } -------------------------------------------------------------------------------- /src/com/mauriciotogneri/jan/kernel/nodes/operations/UnaryNumericNode.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.kernel.nodes.operations; 2 | 3 | import com.mauriciotogneri.jan.compiler.lexical.Token; 4 | import com.mauriciotogneri.jan.kernel.Context; 5 | import com.mauriciotogneri.jan.kernel.Value; 6 | import com.mauriciotogneri.jan.kernel.nodes.PrimitiveNode; 7 | 8 | import java.math.BigDecimal; 9 | 10 | public abstract class UnaryNumericNode extends PrimitiveNode 11 | { 12 | protected UnaryNumericNode(Token token) 13 | { 14 | super(token, 1); 15 | } 16 | 17 | @Override 18 | public Value evaluate(Context context) 19 | { 20 | Value operand = get(0, context); 21 | 22 | if (operand.isNumber()) 23 | { 24 | BigDecimal value = operand.getNumber(); 25 | 26 | return evaluate(value); 27 | } 28 | 29 | // TODO: explain more 30 | throw new RuntimeException("Cannot perform operation '" + token.lexeme + "' at: [" + token.line + ", " + token.column + "]"); 31 | } 32 | 33 | protected abstract Value evaluate(BigDecimal operand); 34 | } -------------------------------------------------------------------------------- /tests/com/mauriciotogneri/jan/tests/CustomProgramOutput.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.tests; 2 | 3 | import com.mauriciotogneri.jan.execution.output.ProgramOutput; 4 | import com.mauriciotogneri.jan.kernel.Value; 5 | 6 | public class CustomProgramOutput implements ProgramOutput 7 | { 8 | public Value result = null; 9 | public String error = null; 10 | 11 | @Override 12 | public void processResult(Value result) 13 | { 14 | this.result = result; 15 | this.error = null; 16 | } 17 | 18 | @Override 19 | public void processError(String text) 20 | { 21 | this.error = text; 22 | this.result = null; 23 | } 24 | 25 | public boolean isValid() 26 | { 27 | return (result != null); 28 | } 29 | } -------------------------------------------------------------------------------- /tests/com/mauriciotogneri/jan/tests/Tests.java: -------------------------------------------------------------------------------- 1 | package com.mauriciotogneri.jan.tests; 2 | 3 | import com.mauriciotogneri.jan.kernel.Jan; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import java.io.BufferedReader; 9 | import java.io.FileInputStream; 10 | import java.io.IOException; 11 | import java.io.InputStreamReader; 12 | 13 | public class Tests 14 | { 15 | private static final String SCRIPTS_FOLDER = "tests/scripts/"; 16 | 17 | @Test 18 | public void testInteger() throws Exception 19 | { 20 | runTest(SCRIPTS_FOLDER + "test_integer.jan"); 21 | } 22 | 23 | @Test 24 | public void testFloat() throws Exception 25 | { 26 | runTest(SCRIPTS_FOLDER + "test_float.jan"); 27 | } 28 | 29 | @Test 30 | public void testBoolean() throws Exception 31 | { 32 | runTest(SCRIPTS_FOLDER + "test_boolean.jan"); 33 | } 34 | 35 | private void runTest(String scriptPath) 36 | { 37 | CustomProgramOutput programOutput = new CustomProgramOutput(); 38 | 39 | Jan jan = new Jan(); 40 | jan.run(scriptPath, programOutput); 41 | 42 | Assert.assertTrue(programOutput.error, programOutput.isValid()); 43 | 44 | Assert.assertEquals(programOutput.result.toString(), getTestResult(scriptPath), programOutput.result.toString()); 45 | } 46 | 47 | private String getTestResult(String filePath) 48 | { 49 | String result = ""; 50 | BufferedReader bufferedReader = null; 51 | 52 | try 53 | { 54 | bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath))); 55 | String line; 56 | 57 | while ((line = bufferedReader.readLine()) != null) 58 | { 59 | result = line; 60 | } 61 | } 62 | catch (Exception e) 63 | { 64 | e.printStackTrace(); 65 | } 66 | finally 67 | { 68 | if (bufferedReader != null) 69 | { 70 | try 71 | { 72 | bufferedReader.close(); 73 | } 74 | catch (IOException e) 75 | { 76 | e.printStackTrace(); 77 | } 78 | } 79 | } 80 | 81 | return (result.length() > 1) ? result.substring(2) : result; 82 | } 83 | } -------------------------------------------------------------------------------- /tests/samples/bool.jan: -------------------------------------------------------------------------------- 1 | true 2 | . 3 | 4 | false 5 | : -------------------------------------------------------------------------------- /tests/samples/list.jan: -------------------------------------------------------------------------------- 1 | head l 2 | 3 | tail l 4 | 5 | last l -------------------------------------------------------------------------------- /tests/samples/math.jan: -------------------------------------------------------------------------------- 1 | abs n 2 | 3 | even n 4 | 5 | odd n 6 | 7 | max a b 8 | 9 | min a b 10 | 11 | sqrt a 12 | 13 | PI 14 | 3.14159265359 -------------------------------------------------------------------------------- /tests/samples/sample.jan: -------------------------------------------------------------------------------- 1 | $ "logic.jan" 2 | $ "math.jan" 3 | $ "list.jan" 4 | 5 | even n ; returns true if n is an even number 6 | = 0 % n 2 7 | 8 | compare a b 9 | ? > a b "A is bigger than B" 10 | ? > b a "B is bigger than A" 11 | "A and B are equal" 12 | 13 | factorial n 14 | ? = n 0 1 ; if (n == 0) return 1 15 | * n factorial - n 1 16 | 17 | ; this is line comment 18 | 19 | fibo index limit list 20 | ? >= index limit list 21 | ? = 0 index fibo 1 limit [ 1 ] 22 | ? = 1 index fibo 2 limit [ 1 1 ] 23 | fibo ++ index limit + + @ - index 1 list @ - index 2 list list 24 | 25 | ; returns the list of the 'n' first numbers in the Fibonacci sequence 26 | fibonacci n 27 | fibo 0 n [ ] 28 | 29 | show_error n 30 | ;? < n 0 { "'n' is less than zero: " n } ; it concatenates all elements between {} 31 | * 2 n 32 | 33 | pi 34 | -3.1415 35 | 36 | name 37 | + + "Arthur" " " "Vandelay" 38 | 39 | list_empty 40 | [ ] 41 | 42 | list_filled 43 | [ 1 2 3 ] 44 | 45 | test_ifs n 46 | ? < n 0 "less than zero" 47 | ?? > n 0 "greater than zero" "equal to zero" 48 | 49 | ; \ fibonacci 10 50 | \ ~ 3 [ 1 2 3 4 5 6 7 ] -------------------------------------------------------------------------------- /tests/scripts/test_boolean.jan: -------------------------------------------------------------------------------- 1 | true 2 | . 3 | 4 | false 5 | : 6 | 7 | ;= != < > <= >= & | ! 8 | 9 | \ [ true false = 1 1.0 = 1 2 = . true = . : = "a" "b" = "" "" ] 10 | ; [true, false, true, false, true, false, false, true] -------------------------------------------------------------------------------- /tests/scripts/test_float.jan: -------------------------------------------------------------------------------- 1 | sum a b 2 | + a b 3 | 4 | diff a b 5 | - a b 6 | 7 | mul a b 8 | * a b 9 | 10 | div a b 11 | / a b 12 | 13 | pow a b 14 | ^ a b 15 | 16 | mod a b 17 | % a b 18 | 19 | inc a 20 | ++ a 21 | 22 | dec a 23 | -- a 24 | 25 | \ [ sum 1.1 2.9 diff 4 7.3 mul 2 3.6 div 8 3 pow 2 4.7 mod 12 2.4 inc 10.4 dec 0.1 ] 26 | ; [4.0, -3.3, 7.2, 2.6666666667, 16, 0.0, 11.4, -0.9] -------------------------------------------------------------------------------- /tests/scripts/test_integer.jan: -------------------------------------------------------------------------------- 1 | sum a b 2 | + a b 3 | 4 | diff a b 5 | - a b 6 | 7 | mul a b 8 | * a b 9 | 10 | div a b 11 | / a b 12 | 13 | pow a b 14 | ^ a b 15 | 16 | mod a b 17 | % a b 18 | 19 | inc a 20 | ++ a 21 | 22 | dec a 23 | -- a 24 | 25 | \ [ sum 1 2 diff 4 9 mul 2 3 div 8 2 pow 3 4 mod 12 5 inc 10 dec 0 ] 26 | ; [3, -5, 6, 4, 81, 2, 11, -1] --------------------------------------------------------------------------------