├── .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 extends JavaFileObject> 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]
--------------------------------------------------------------------------------