├── .gitignore ├── LICENSE.txt ├── Makefile ├── README.md ├── core ├── core.huo ├── numbers.huo └── strings.huo ├── examples ├── array.txt ├── array.txt.out ├── conditional.txt ├── conditional.txt.out ├── each.txt ├── each.txt.out ├── eval.txt ├── eval.txt.out ├── first-class.txt ├── for_do.txt ├── for_do.txt.out ├── imports.txt ├── imports.txt.out ├── let.txt ├── let.txt.out ├── library.txt ├── library.txt.out ├── parallel.txt ├── parallel.txt.out ├── reduce.txt ├── reduce.txt.out ├── return.txt ├── return.txt.out ├── strings.txt ├── strings.txt.out ├── while.txt └── while.txt.out ├── repl.huo └── src ├── apply_core_function.c ├── apply_core_function.h ├── apply_execution_function.c ├── apply_execution_function.h ├── apply_single_value_func.c ├── apply_single_value_func.h ├── base_util.c ├── base_util.h ├── config.c ├── config.h ├── constants.c ├── constants.h ├── core_functions.c ├── core_functions.h ├── execute.c ├── execute.h ├── execution_functions ├── evaluate.c ├── evaluate.h ├── for_each.c ├── for_each.h ├── for_loop.c ├── for_loop.h ├── if_block.c ├── if_block.h ├── let_binding.c ├── let_binding.h ├── map_array.c ├── map_array.h ├── parallel_execution.c ├── parallel_execution.h ├── read_file.c ├── read_file.h ├── read_line.c ├── read_line.h ├── reduce.c ├── reduce.h ├── reduce_ast.c ├── reduce_ast.h ├── switch.c ├── switch.h ├── while_loop.c └── while_loop.h ├── huo.c ├── huo.h ├── parser.c ├── parser.h ├── path_utils.c ├── path_utils.h ├── process_defs.c ├── process_defs.h ├── store_defs.c ├── store_defs.h ├── structures ├── array.c ├── array.h ├── hash_table.c ├── hash_table.h ├── huo_ast.c ├── huo_ast.h ├── string.c ├── string.h ├── structures.h ├── token.c ├── token.h ├── tokens.c ├── tokens.h ├── value.c ├── value.h ├── varint.c └── varint.h ├── tokenizer.c └── tokenizer.h /.gitignore: -------------------------------------------------------------------------------- 1 | huo 2 | *.o 3 | *.mk 4 | *~ 5 | *.exe 6 | .vscode/ 7 | *.exe.stackdump 8 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 James Howe Edwards 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS += -g3 2 | LIBS = -lpthread 3 | 4 | # Be super strict about everything 5 | CFLAGS += -std=c11 -Wall -Wextra -pedantic -O2 6 | CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 7 | 8 | # Automatically sort out header dependencies 9 | CPPFLAGS += -MD -MF $(patsubst src/%.o,.%.mk,$@) -MP 10 | -include $(patsubst %.o,.%.mk,$(obj)) 11 | 12 | CPPFLAGS += -MD -MF $(patsubst src/execution_functions/%.o,.%.mk,$@) -MP 13 | -include $(patsubst %.o,.%.mk,$(obj)) 14 | 15 | CPPFLAGS += -MD -MF $(patsubst src/structures/%.o,.%.mk,$@) -MP 16 | -include $(patsubst %.o,.%.mk,$(obj)) 17 | 18 | LDFLAGS += -rdynamic 19 | 20 | 21 | objs = \ 22 | src/structures/array.o \ 23 | src/structures/huo_ast.o \ 24 | src/structures/string.o \ 25 | src/structures/value.o \ 26 | src/structures/hash_table.o \ 27 | src/structures/token.o \ 28 | src/constants.o \ 29 | src/base_util.o \ 30 | src/core_functions.o \ 31 | src/apply_core_function.o \ 32 | src/execution_functions/parallel_execution.o\ 33 | src/execution_functions/for_each.o\ 34 | src/execution_functions/for_loop.o\ 35 | src/execution_functions/map_array.o\ 36 | src/execution_functions/reduce.o\ 37 | src/execution_functions/read_file.o\ 38 | src/execution_functions/let_binding.o\ 39 | src/execution_functions/reduce_ast.o\ 40 | src/execution_functions/if_block.o\ 41 | src/execution_functions/switch.o\ 42 | src/execution_functions/while_loop.o\ 43 | src/execution_functions/evaluate.o\ 44 | src/execution_functions/read_line.o\ 45 | src/apply_execution_function.o\ 46 | src/apply_single_value_func.o\ 47 | src/tokenizer.o \ 48 | src/process_defs.o \ 49 | src/store_defs.o \ 50 | src/parser.o \ 51 | src/execute.o \ 52 | src/config.o \ 53 | src/path_utils.o \ 54 | src/huo.o 55 | 56 | all: huo 57 | 58 | huo: $(objs) 59 | $(CC) $(LDFLAGS) -o huo $(objs) $(LIBS) 60 | 61 | clean: ; rm -f -- ./src/*.mk ./src/*.o & rm -f ./src/execution_functions/*.o & rm -f ./src/structures/*.o & rm -f ./.*.mk 62 | 63 | .PHONY: all clean 64 | .DELETE_ON_ERROR: 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # huo 2 | Huo is an interpreted language which I started as a hobby project. The original vision for Huo was to be simple and have some cool native features like matrix math and parallel processing. The interpreter is fairly small and easy to work with and the syntax is easy to understand. Huo means "living" or "fire" in Chinese. It's pretty hard to pronounce, so if you don't know Chinese you can just say "hoo-ah". 3 | 4 | If you would like to contribute to Huo open an issue describing the work you would like to do. If the change is accepted then you can make a pull request with your changes and it will be merged in after review. 5 | 6 | ## compile 7 | ```shell 8 | make 9 | ``` 10 | 11 | ## run 12 | Create a file containing Huo code and run it with the interpreter: 13 | ```shell 14 | $ ./huo test.huo 15 | ``` 16 | Or you can run the included REPL which is written in Huo. To exit the REPL simply type "exit". 17 | ```shell 18 | ./huo repl.huo 19 | :huo:> (print "Hello, world!") 20 | "Hello, world!" 21 | ``` 22 | 23 | ## Functions 24 | 25 | basic math 26 | ```lisp 27 | (+ 3 (* 4 3)) ; 15 28 | 29 | (+ 3 -3.5) ; -0.500000 30 | 31 | (+ 3 (/ 10 4)) ; 5.500000 32 | 33 | (* 3 (- 10 4)) ; 18 34 | ``` 35 | math operations map over arrays 36 | ```lisp 37 | (+ [1,2] [3,4]) ; [4, 6] 38 | (* [1,2] [3,4]) ; [3, 8] 39 | ``` 40 | print 41 | ```lisp 42 | (print (* 3 6)) ; prints 18 to the console 43 | (print "hello world") ; prints "hello world" to the console 44 | (let x (print "Hello")) ; prints "Hello" and stores undefined in x 45 | ``` 46 | concat strings and arrays 47 | ```lisp 48 | (cat "hello " "world!") ; "hello world!" 49 | (cat [1,2] [3,4]) ; [1, 2, 3, 4] 50 | ``` 51 | length of strings and arrays 52 | ```lisp 53 | (length "Hello") ; 5 54 | (length [1,2,3,4,5] ; 5 55 | ``` 56 | item at index of strings and arrays 57 | ```lisp 58 | (index 1 [1,2,3,4]) ; 2 59 | (index 1 "Open") ; "p" 60 | ``` 61 | set item at index of strings and arrays 62 | ```lisp 63 | (set 3 "B" "oooooo") ; "oooBoo" 64 | (set 3 "B" [1, 2, 3, 4]) ; [1, 2, 3, "B"] 65 | ``` 66 | substring and split on strings 67 | ```lisp 68 | (substring 0 4 "hello world") ; "hell" 69 | (split "o" "hello world"); [ "hell", " w", "rld" ] 70 | ``` 71 | equals, not, greater than and less than 72 | ```lisp 73 | (= 3 2) ; false 74 | (= "Hey" "Hey") ; true 75 | (! 1 3) ; true 76 | (! "Hey" (cat "He" "y")) ; false 77 | (> 4 3) ; true 78 | (< 10 1) ; false 79 | ``` 80 | and, or, boolean primitives 81 | ```lisp 82 | (& true false) ; false 83 | (| true false) ; true 84 | (& (! true false) (= true true)); true 85 | ``` 86 | if block 87 | ```lisp 88 | ; the if block requires three functions: conditional, true result and false result 89 | ; to do an else-if just put another if block in the false result position 90 | (if (> 3 4) 91 | (print "normal math") 92 | (print "backwards land math") 93 | ) 94 | ``` 95 | let bindings 96 | ```lisp 97 | ; let bindings are stored in a key-value structure and are passed 98 | ; by reference which means they are mutable 99 | (let x 5) 100 | (let y []) 101 | (push 5 y) 102 | (print (+ x 3) ; 8 103 | (print y) ; [ 5 ] 104 | ``` 105 | the def function allows you to define functions with any number of parameters 106 | the arguments to def are: the function name, any number of parameters, the function body 107 | ```lisp 108 | (def biggest x y (if (> x y) x y)) 109 | (def sum x (reduce x acc curr (+ acc curr) 0)) 110 | (sum [1,2,3,4]) ; 10 111 | (biggest 10 5) ; 10 112 | ``` 113 | def expects a function as its final parameter 114 | if you want to simply return a composition of values, use the return function 115 | ```lisp 116 | (def pair x y (return [x, y])) 117 | (let x (pair 0 "start")) 118 | (print x) ; [ 0, "start" ] 119 | ``` 120 | ast and run together allow you to pass functions as arguments 121 | the keywork ast returns its first argument as a value of type ast 122 | the keyword run will execute an ast value with whatever arguments you pass in 123 | ```lisp 124 | (def mapper arr fnc 125 | (do 126 | (each arr item i 127 | (set i (run fnc item) arr) 128 | ) 129 | (return arr) 130 | ) 131 | ) 132 | 133 | (msg_first "Hello" (ast (cat x " World"))) 134 | ``` 135 | switch block 136 | ```lisp 137 | ; the switch block is convenient for matching a value against a large number 138 | ; of possibilities ~ the switch block takes a value and a list of cases 139 | ; each case is a comparator, a value, and a return value/function if the comparator is true 140 | ; include a default case to catch unhandled conditions 141 | (def describe_number x 142 | (switch x 143 | (> 100 "That's a huge number!") 144 | (> 50 "Hmm, not so big, less than one hundred.") 145 | (> 20 "I supoooose that's a decently sized number.") 146 | (< 10 "Pfft, you call that a number?") 147 | (default "I have no words...") 148 | ) 149 | ) 150 | (describe_number 110) ; "That's a huge number!" 151 | (describe_number "Apple"); "I have no words..." 152 | ``` 153 | core functions will map over nested arrays 154 | ```lisp 155 | (let y [[1,2], [3,4]]) 156 | (let z [[3,4], [5,6]]) 157 | (print (+ y z)) ; [[4,6], [8,10]] 158 | (> [[1, 2], [56, 123]] [[8, 9], [3,4]]) ; [ [ False, False ], [ True, True ] ] 159 | ``` 160 | push takes an item and an array in that order 161 | ```lisp 162 | (push 5 [1, 2, 3, 4]) ; [1, 2, 3, 4, 5] 163 | ``` 164 | 165 | map and each both take four arguments: 166 | first the array you want to iterate over 167 | the names for the current item and the index 168 | and then the function to call each iteration 169 | ```lisp 170 | (let x [1, 2, 3]) 171 | (let y 0) 172 | (each x num idx (let y (+ y num))) 173 | (print y) ; 6 174 | (map x num idx (+ num idx)) 175 | (print x) ; [1, 3, 5] 176 | ``` 177 | reduce is takes the array to iterate over, 178 | the names of the accumulator and the current item, the function to 179 | call each iteration, and an optional initial value for the accumulator 180 | ```lisp 181 | (def avg x 182 | (/ 183 | (reduce x acc cur (+ acc cur)) 184 | (length x) 185 | ) 186 | ) 187 | (let x [1,2,3,4,13]) 188 | (print (reduce (push 4 [1,2,3]) acc cur (+ acc cur) 0)) ; 10 189 | (print (avg x)) ; 4.600000 190 | ``` 191 | the for loop takes three arguments 192 | start number, end number, function to call each iteration 193 | start and end can be functions that return numbers 194 | ```lisp 195 | (let x []) 196 | (for 0 10 197 | (set (length x) 0 x) 198 | ) 199 | (print x) ; -> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 200 | ``` 201 | the do block is a function that takes n functions and executes them 202 | in order, returning the value from the last function inside it 203 | ```lisp 204 | (def factorial x 205 | (do 206 | (let z [ ]) 207 | (for 0 x 208 | (set (length z) (+ (length z) 1) z) 209 | ) 210 | (reduce z acc cur (* acc cur) 1) 211 | ) 212 | ) 213 | ``` 214 | reading a file is simple and returns a string 215 | ```lisp 216 | (let file (read "./files/example.txt")) 217 | (print file) ; prints contents of example.txt 218 | ``` 219 | you can import a huo file that contains functions definitions 220 | the import function will ignore everything but functions 221 | ```lisp 222 | (import "./math.huo") ; import file containing average function 223 | (let x (average [1,2,3,4,5,6] )) ; use imported function 224 | ``` 225 | -------------------------------------------------------------------------------- /core/core.huo: -------------------------------------------------------------------------------- 1 | (import "core/strings.huo") 2 | (import "core/numbers.huo") 3 | -------------------------------------------------------------------------------- /core/numbers.huo: -------------------------------------------------------------------------------- 1 | (def max x y (if (> x y)(return x)(return y))) 2 | 3 | (def min x y (if (< x y)(return x)(return y))) 4 | 5 | (def char_to_int str 6 | (switch str 7 | (= "1" (return 1)) 8 | (= "2" (return 2)) 9 | (= "3" (return 3)) 10 | (= "4" (return 4)) 11 | (= "5" (return 5)) 12 | (= "6" (return 6)) 13 | (= "7" (return 7)) 14 | (= "8" (return 8)) 15 | (= "9" (return 9)) 16 | (= "0" (return 0)) 17 | ) 18 | ) 19 | 20 | (def exponent n x 21 | (do 22 | (let result n) 23 | (for 1 x 24 | (let result (* result n)) 25 | ) 26 | (return result) 27 | ) 28 | ) 29 | 30 | (def str_to_int str 31 | (do 32 | (let counter (- (length str) 1)) 33 | (let i 0) 34 | (let result 0) 35 | (for 0 (length str) 36 | (do 37 | (let result 38 | (+ result 39 | (if (> counter 1) 40 | (* 41 | (char_to_int (index i str)) 42 | (exponent 10 counter) 43 | ) 44 | (if (> counter 0) 45 | (* (char_to_int (index i str)) 10) 46 | (char_to_int (index i str))) 47 | ) 48 | ) 49 | ) 50 | (let counter (- counter 1)) 51 | (let i (+ i 1)) 52 | ) 53 | ) 54 | (return result) 55 | ) 56 | ) 57 | 58 | (def exponent x n 59 | (switch n 60 | (= 0 1) 61 | (= 1 x) 62 | (< 1 (do 63 | (let result x) 64 | (for 1 n (do 65 | (let result (* result x)) 66 | ) 67 | ) 68 | (return result) 69 | ) 70 | ) 71 | (> 0 (do 72 | (let result 1) 73 | (for 0 n (let result (/ result x))) 74 | (return result) 75 | ) 76 | ) 77 | ) 78 | ) 79 | 80 | (def cross_product x y 81 | (do 82 | (let result []) 83 | (each x xitem xidx 84 | (do 85 | (set xidx [] result) 86 | (each y yitem yidx 87 | (do 88 | (let sum 0) 89 | (each (index xidx x) kitem kidx 90 | (let sum 91 | (+ sum 92 | (* 93 | (index kidx (index xidx x)) 94 | (index yidx (index kidx y)) 95 | ) 96 | ) 97 | ) 98 | ) 99 | (set yidx sum (index xidx result)) 100 | ) 101 | ) 102 | ) 103 | ) 104 | (return result) 105 | ) 106 | ) 107 | -------------------------------------------------------------------------------- /core/strings.huo: -------------------------------------------------------------------------------- 1 | (def join arr str 2 | (reduce arr acc cur (cat (cat acc str) cur)) 3 | ) 4 | 5 | (def char_to_uppercase str 6 | (switch str 7 | (= "a" (return "A")) 8 | (= "b" (return "B")) 9 | (= "c" (return "C")) 10 | (= "d" (return "D")) 11 | (= "e" (return "E")) 12 | (= "f" (return "F")) 13 | (= "g" (return "G")) 14 | (= "h" (return "H")) 15 | (= "i" (return "I")) 16 | (= "j" (return "J")) 17 | (= "k" (return "K")) 18 | (= "l" (return "L")) 19 | (= "m" (return "M")) 20 | (= "n" (return "N")) 21 | (= "o" (return "O")) 22 | (= "p" (return "P")) 23 | (= "q" (return "Q")) 24 | (= "r" (return "R")) 25 | (= "s" (return "S")) 26 | (= "t" (return "T")) 27 | (= "u" (return "U")) 28 | (= "v" (return "V")) 29 | (= "w" (return "W")) 30 | (= "x" (return "X")) 31 | (= "y" (return "Y")) 32 | (= "z" (return "Z")) 33 | (default (return str)) 34 | ) 35 | ) 36 | (def char_to_lowercase str 37 | (switch str 38 | (= "A" (return "a")) 39 | (= "B" (return "b")) 40 | (= "C" (return "c")) 41 | (= "D" (return "d")) 42 | (= "E" (return "e")) 43 | (= "F" (return "f")) 44 | (= "G" (return "g")) 45 | (= "H" (return "h")) 46 | (= "I" (return "i")) 47 | (= "J" (return "j")) 48 | (= "K" (return "k")) 49 | (= "L" (return "l")) 50 | (= "M" (return "m")) 51 | (= "N" (return "n")) 52 | (= "O" (return "o")) 53 | (= "P" (return "p")) 54 | (= "Q" (return "q")) 55 | (= "R" (return "r")) 56 | (= "S" (return "s")) 57 | (= "T" (return "t")) 58 | (= "U" (return "u")) 59 | (= "V" (return "v")) 60 | (= "W" (return "w")) 61 | (= "X" (return "x")) 62 | (= "Y" (return "y")) 63 | (= "Z" (return "z")) 64 | (default (return str)) 65 | ) 66 | ) 67 | 68 | (def str_to_uppercase str 69 | (do 70 | (each str chr idx 71 | (do 72 | (let str (set idx (char_to_uppercase chr) str)) 73 | ) 74 | ) 75 | (return str) 76 | ) 77 | ) 78 | 79 | (def str_to_lowercase str 80 | (do 81 | (each str chr idx 82 | (do 83 | (let str (set idx (char_to_uppercase chr) str)) 84 | ) 85 | ) 86 | (return str) 87 | ) 88 | ) 89 | -------------------------------------------------------------------------------- /examples/array.txt: -------------------------------------------------------------------------------- 1 | (let x [1,2,3,4]) 2 | (print x) 3 | (print (length x)) 4 | (print (index 3 x)) 5 | (print (push 5 x)) 6 | (let z [1, 2, [4, 5, [1, 2]]]) 7 | (print z) 8 | (print (index 2 z)) 9 | (let a [[1, 2], [3, 4]]) 10 | (let b [[5, 4], [2, 2]]) 11 | (print (+ b a)) 12 | (print (* b a)) 13 | (set 0 1 a) 14 | (print a) 15 | -------------------------------------------------------------------------------- /examples/array.txt.out: -------------------------------------------------------------------------------- 1 | [ 1, 2, 3, 4 ] 2 | 4 3 | 4 4 | [ 1, 2, 3, 4, 5 ] 5 | [ 1, 2, [ 4, 5, [ 1, 2 ] ] ] 6 | [ 4, 5, [ 1, 2 ] ] 7 | [ [ 6, 6 ], [ 5, 6 ] ] 8 | [ [ 6, 6 ], [ 5, 6 ] ] 9 | [ 1, [ 3, 4 ] ] 10 | -------------------------------------------------------------------------------- /examples/conditional.txt: -------------------------------------------------------------------------------- 1 | (print 2 | (if 3 | (> 3 4) 4 | (+ 3 1) 5 | (if (> 1.0 (+ 0.5 0.5)) 6 | (print "Hey!") 7 | (print "Oops!") 8 | ) 9 | ) 10 | ) 11 | -------------------------------------------------------------------------------- /examples/conditional.txt.out: -------------------------------------------------------------------------------- 1 | 4 2 | -------------------------------------------------------------------------------- /examples/each.txt: -------------------------------------------------------------------------------- 1 | (let x 0) 2 | (let y [1, 5, 3, 4, 7, 9, 6, 8]) 3 | (each y item i (let x (+ x item))) 4 | (print (/ x (length y))) 5 | (map y item i (+ item i)) 6 | (print y) 7 | -------------------------------------------------------------------------------- /examples/each.txt.out: -------------------------------------------------------------------------------- 1 | 5.375000 2 | [ 1, 6, 5, 7, 11, 14, 12, 15 ] 3 | -------------------------------------------------------------------------------- /examples/eval.txt: -------------------------------------------------------------------------------- 1 | (eval "(print (+ 10 5))") 2 | (eval "(def add_five x (+ 5 x))") 3 | (eval "(print (add_five 20))") 4 | -------------------------------------------------------------------------------- /examples/eval.txt.out: -------------------------------------------------------------------------------- 1 | 15 2 | 25 3 | -------------------------------------------------------------------------------- /examples/first-class.txt: -------------------------------------------------------------------------------- 1 | (def msg_first msg fnc 2 | (do 3 | (print msg) 4 | (print (run fnc msg)) 5 | ) 6 | ) 7 | 8 | (def mapper arr fnc 9 | (do 10 | (each arr item i 11 | (set i (run fnc item) arr) 12 | ) 13 | (return arr) 14 | ) 15 | ) 16 | 17 | (msg_first "Hello" (ast (cat x " World"))) 18 | 19 | (print (mapper [1, 2, 3] (ast (+ item 3)))) 20 | -------------------------------------------------------------------------------- /examples/for_do.txt: -------------------------------------------------------------------------------- 1 | (let x 1) 2 | (for 0 50 3 | (let x (+ x x)) 4 | ) 5 | (print x) 6 | (let y [ 1 ]) 7 | (for 0 25 8 | (do 9 | (print 1) 10 | (set (length y) (length y) y) 11 | ) 12 | ) 13 | (print y) 14 | (print (reduce y acc cur (do 15 | (let x (* acc 98)) 16 | (/ x cur) 17 | ) 1 )) 18 | -------------------------------------------------------------------------------- /examples/for_do.txt.out: -------------------------------------------------------------------------------- 1 | 1125899906842624 2 | 0 3 | 1 4 | 2 5 | 3 6 | 4 7 | 5 8 | 6 9 | 7 10 | 8 11 | 9 12 | 10 13 | 11 14 | 12 15 | 13 16 | 14 17 | 15 18 | 16 19 | 17 20 | 18 21 | 19 22 | 20 23 | 21 24 | 22 25 | 23 26 | 24 27 | [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 ] 28 | -------------------------------------------------------------------------------- /examples/imports.txt: -------------------------------------------------------------------------------- 1 | (import "examples/library.txt") 2 | (print (factorial 20)) 3 | (print (avg [1,2,3,4,5,6,7,-8, 123, 45, 2, 67, -1657, 4, -6.6, 9])) 4 | -------------------------------------------------------------------------------- /examples/imports.txt.out: -------------------------------------------------------------------------------- 1 | 2432902008176640000 2 | 4.500000 3 | -------------------------------------------------------------------------------- /examples/let.txt: -------------------------------------------------------------------------------- 1 | (print (+ 1 3)) 2 | -------------------------------------------------------------------------------- /examples/let.txt.out: -------------------------------------------------------------------------------- 1 | 25 2 | -------------------------------------------------------------------------------- /examples/library.txt: -------------------------------------------------------------------------------- 1 | (def factorial x 2 | (do 3 | (let z [ ]) 4 | (for 0 x 5 | (set (length z) (+ (length z) 1) z) 6 | ) 7 | (reduce z acc cur (* acc cur) 1) 8 | ) 9 | ) 10 | (def avg x 11 | (/ 12 | (reduce x acc cur (+ acc cur)) 13 | (length x) 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /examples/library.txt.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuoLanguage/huo/66394147a034d89e48aff394166d7afe62c21cf6/examples/library.txt.out -------------------------------------------------------------------------------- /examples/parallel.txt: -------------------------------------------------------------------------------- 1 | (let x 0) 2 | (let y []) 3 | (parallel 4 | (for 0 999 (let x (+ x 1))) 5 | (for 0 999 (set (length y) (length y) y)) 6 | ) 7 | (print x) 8 | (print y) 9 | -------------------------------------------------------------------------------- /examples/parallel.txt.out: -------------------------------------------------------------------------------- 1 | 999 2 | [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998 ] 3 | -------------------------------------------------------------------------------- /examples/reduce.txt: -------------------------------------------------------------------------------- 1 | (def avg x 2 | (/ 3 | (reduce x acc cur (+ acc cur)) 4 | (length x) 5 | ) 6 | ) 7 | (let x [1,2,3,4,13]) 8 | (print (reduce (push 4 [1,2,3]) acc cur (+ acc cur) 0)) 9 | (print (avg x)) 10 | -------------------------------------------------------------------------------- /examples/reduce.txt.out: -------------------------------------------------------------------------------- 1 | 10 2 | 4.600000 3 | -------------------------------------------------------------------------------- /examples/return.txt: -------------------------------------------------------------------------------- 1 | (def pair x y (return [x, y])) 2 | (def nest x y (return [x, [1, y]])) 3 | (let x (pair 10 1)) 4 | (let y (nest "hey" "you")) 5 | (print x) 6 | (print y) 7 | -------------------------------------------------------------------------------- /examples/return.txt.out: -------------------------------------------------------------------------------- 1 | [ 10, 1 ] 2 | [ "hey", [ 1, "y" ] ] 3 | -------------------------------------------------------------------------------- /examples/strings.txt: -------------------------------------------------------------------------------- 1 | (import "core/core.huo") 2 | (def join arr str 3 | (reduce arr acc cur (cat (cat acc str) cur)) 4 | ) 5 | (let x "hello_world_of_great_programming_languages") 6 | (let y (substring 0 4 x)) 7 | 8 | (let z (split "_" x)) 9 | (print (join z " ")) 10 | (print (str_to_uppercase x)) 11 | -------------------------------------------------------------------------------- /examples/strings.txt.out: -------------------------------------------------------------------------------- 1 | "hello world of great programming languages" 2 | -------------------------------------------------------------------------------- /examples/while.txt: -------------------------------------------------------------------------------- 1 | (let x [0]) 2 | (let y 1) 3 | (while 4 | (< (length x) 100000) 5 | (do 6 | (let y (+ 1 y)) 7 | (push y x) 8 | ) 9 | 10 | ) 11 | (print x) 12 | (print (length x)) 13 | -------------------------------------------------------------------------------- /examples/while.txt.out: -------------------------------------------------------------------------------- 1 | [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] 2 | 10001 3 | -------------------------------------------------------------------------------- /repl.huo: -------------------------------------------------------------------------------- 1 | (let huo_repl_input "") 2 | 3 | (while (! huo_repl_input "exit") 4 | (do 5 | (let huo_repl_input (readline ":huo:> ")) 6 | (if (! huo_repl_input "exit") 7 | (print (eval huo_repl_input)) 8 | (print "exiting...") 9 | ) 10 | ) 11 | ) 12 | -------------------------------------------------------------------------------- /src/apply_core_function.c: -------------------------------------------------------------------------------- 1 | #include "apply_core_function.h" 2 | #include "constants.h" 3 | #include "structures/structures.h" 4 | #include "core_functions.h" 5 | #include "base_util.h" 6 | #include "config.h" 7 | #include "execution_functions/let_binding.h" 8 | 9 | struct Value apply_core_function(struct Value *kwd_val, struct Execution_bundle *exec_bundle __attribute((unused)), struct Value *a, struct Value *b) { 10 | struct String kwd = value_as_keyword(kwd_val); 11 | struct Value v; 12 | if(string_matches_heap(&kwd, &concat_const)){ 13 | v = concat(*a, *b); 14 | } 15 | else if(string_matches_heap(&kwd, &index_const)){ 16 | v = value_index(*a, *b); 17 | } 18 | else if(string_matches_heap(&kwd, &push_const)){ 19 | v = push(*a, *b); 20 | } 21 | else if(string_matches_heap(&kwd, &split_const)){ 22 | v = split(*a, *b); 23 | } else if (a->type == TYPE_ARRAY && b->type == TYPE_ARRAY) { 24 | struct Value_array *a_arr = value_as_array(a); 25 | struct Value_array *b_arr = value_as_array(b); 26 | if(a_arr->size != b_arr->size){ 27 | ERROR("Tried to map over arrays of different sizes: %zu != %zu", a_arr->size, b_arr->size); 28 | } 29 | for(size_t i = 0; i < a_arr->size; i++){ 30 | struct Value result = apply_core_function(kwd_val, exec_bundle, a_arr->values[i], b_arr->values[i]); 31 | value_copy_to(a_arr->values[i], &result); 32 | } 33 | return *a; 34 | } else if(string_matches_char(&kwd, '*')){ 35 | v = mul(*a, *b); 36 | } else if(string_matches_char(&kwd, '+')){ 37 | v = add(*a, *b); 38 | } else if(string_matches_char(&kwd, '-')){ 39 | v = sub(*a, *b); 40 | } else if(string_matches_char(&kwd, '/')){ 41 | v = divide(*a, *b); 42 | } else if(string_matches_char(&kwd, '!')){ 43 | v = not(*a, *b); 44 | } else if(string_matches_char(&kwd, '=')){ 45 | v = equals(*a, *b); 46 | } else if(string_matches_char(&kwd, '>')){ 47 | v = greater_than(*a, *b); 48 | } else if(string_matches_char(&kwd, '<')){ 49 | v = greater_than(*b, *a); 50 | } else if(string_matches_char(&kwd, '&')){ 51 | v = and(*a, *b); 52 | } else if(string_matches_char(&kwd, '|')){ 53 | v = or(*a, *b); 54 | } else { 55 | return *a; 56 | } 57 | *a = v; 58 | return v; 59 | } 60 | -------------------------------------------------------------------------------- /src/apply_core_function.h: -------------------------------------------------------------------------------- 1 | #ifndef APPLY_CORE_FUNCTION_H 2 | #define APPLY_CORE_FUNCTION_H 1 3 | 4 | #include "structures/structures.h" 5 | 6 | struct Value apply_core_function(struct Value *kwd_val, struct Execution_bundle *exec_bundle, struct Value *a, struct Value *b); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/apply_execution_function.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "structures/structures.h" 4 | #include "core_functions.h" 5 | #include "base_util.h" 6 | #include "process_defs.h" 7 | #include "store_defs.h" 8 | #include "constants.h" 9 | #include "execute.h" 10 | #include "execution_functions/for_each.h" 11 | #include "execution_functions/for_loop.h" 12 | #include "execution_functions/reduce.h" 13 | #include "execution_functions/read_file.h" 14 | #include "execution_functions/map_array.h" 15 | #include "execution_functions/if_block.h" 16 | #include "execution_functions/let_binding.h" 17 | #include "execution_functions/switch.h" 18 | #include "execution_functions/parallel_execution.h" 19 | #include "execution_functions/while_loop.h" 20 | 21 | 22 | bool apply_execution_function(struct Value *kwd_val, struct Value *result, struct Execution_bundle * exec_bundle){ 23 | huo_ast * ast = exec_bundle->ast; 24 | 25 | 26 | //printf("AEF: %s\n", string_to_chars(ast_to_string(ast))); 27 | 28 | struct Value undefined = value_from_undef(); 29 | 30 | struct String kwd = value_as_keyword(kwd_val); 31 | 32 | if(string_matches_heap(&kwd, &if_const)){ 33 | *result = if_block(exec_bundle); 34 | return true; 35 | } 36 | else if(string_matches_heap(&kwd, &each_const)){ 37 | for_each(exec_bundle); 38 | *result = undefined; 39 | return true; 40 | } 41 | else if(string_matches_heap(&kwd, &map_const)){ 42 | *result = map_array(exec_bundle); 43 | return true; 44 | } 45 | else if(string_matches_heap(&kwd, &while_const)){ 46 | while_loop(exec_bundle); 47 | *result = undefined; 48 | return true; 49 | } 50 | else if(string_matches_heap(&kwd, &reduce_const)){ 51 | *result = reduce_array(exec_bundle); 52 | return true; 53 | } 54 | else if(string_matches_heap(&kwd, &set_const)) { 55 | if (ast_size(ast) != 4) { 56 | ERROR("Not enough arguments for set: %zu < 4", ast_size(ast)); 57 | } 58 | exec_bundle->ast = ast_child(ast, 1); 59 | struct Value index = execute(exec_bundle); 60 | 61 | exec_bundle->ast = ast_child(ast, 2); 62 | struct Value item = execute(exec_bundle); 63 | 64 | exec_bundle->ast = ast_child(ast, 3); 65 | struct Value array = execute(exec_bundle); 66 | 67 | exec_bundle->ast = ast; 68 | 69 | set(index, item, &array); 70 | *result = array; 71 | return true; 72 | } 73 | else if(string_matches_heap(&kwd, &for_const)){ 74 | for_loop(exec_bundle); 75 | *result = undefined; 76 | return true; 77 | } 78 | else if(string_matches_heap(&kwd, &do_const)){ 79 | if (ast_size(ast) <= 1) { 80 | ERROR("Not enough arguments for do: %zu < 1", ast_size(ast)); 81 | } 82 | for(size_t i = 1; i < ast_size(ast); i++){ 83 | exec_bundle->ast = ast_child(ast, i); 84 | *result = execute(exec_bundle); 85 | } 86 | exec_bundle->ast = ast; 87 | return true; 88 | } 89 | else if(string_matches_heap(&kwd, &substring_const)){ 90 | if (ast_size(ast) != 4) { 91 | ERROR("Not enough arguments for substring: %zu < 4", ast_size(ast)); 92 | } 93 | 94 | exec_bundle->ast = ast_child(ast, 1); 95 | struct Value start = execute(exec_bundle); 96 | exec_bundle->ast = ast_child(ast, 2); 97 | struct Value end = execute(exec_bundle); 98 | exec_bundle->ast = ast_child(ast, 3); 99 | struct Value string = execute(exec_bundle); 100 | 101 | exec_bundle->ast = ast; 102 | 103 | *result = substring(start, end, string); 104 | return true; 105 | } 106 | else if(string_matches_heap(&kwd, &switch_const)){ 107 | *result = switch_case(exec_bundle); 108 | return true; 109 | } 110 | else if(string_matches_heap(&kwd, ¶llel_const)){ 111 | parallel_execution(exec_bundle); 112 | *result = undefined; 113 | return true; 114 | } 115 | else if(string_matches_heap(&kwd, &let_const)){ 116 | struct Value *name = ast_value(ast_child(ast, 1)); 117 | 118 | exec_bundle->ast = ast_copy(ast_child(ast, 2)); 119 | struct Value val = execute(exec_bundle); 120 | 121 | exec_bundle->ast = ast; 122 | 123 | store_let_value(name, &val, exec_bundle->scopes); 124 | 125 | 126 | *result = value_from_undef(); 127 | return true; 128 | } 129 | else if(string_matches_heap(&kwd, &def_const)){ 130 | 131 | struct Value *name = ast_value(ast_child(ast, 1)); 132 | 133 | store_def_func(name, ast, exec_bundle->scopes); 134 | *result = value_from_undef(); 135 | return true; 136 | } 137 | else if(string_matches_heap(&kwd, &run_const)){ 138 | exec_bundle->ast = ast_child(ast, 1); 139 | struct Value fn_value = execute(exec_bundle); 140 | huo_ast *fn = value_as_ast(&fn_value); 141 | size_t index = 1; 142 | for(size_t i = 2; i < ast_size(ast); i++){ 143 | ast_set_child(fn, index, ast_child(ast, i)); 144 | index++; 145 | } 146 | 147 | exec_bundle->ast = fn; 148 | *result = execute(exec_bundle); 149 | exec_bundle->ast = ast; 150 | return true; 151 | } 152 | else if(string_matches_heap(&kwd, &ast_const)){ 153 | 154 | *result = value_from_ast(ast_copy(ast_child(ast, 1))); 155 | return true; 156 | } 157 | return false; 158 | } 159 | -------------------------------------------------------------------------------- /src/apply_execution_function.h: -------------------------------------------------------------------------------- 1 | #ifndef _APPLY_EXECUTION_FUNCTION_H 2 | #define _APPLY_EXECUTION_FUNCTION_H 3 | 4 | #include "structures/structures.h" 5 | 6 | bool apply_execution_function(struct Value *kwd_val, struct Value *ret, struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/apply_single_value_func.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "structures/structures.h" 4 | #include "core_functions.h" 5 | #include "base_util.h" 6 | #include "process_defs.h" 7 | #include "store_defs.h" 8 | #include "constants.h" 9 | #include "execute.h" 10 | #include "execution_functions/read_line.h" 11 | #include "execution_functions/read_file.h" 12 | #include "execution_functions/evaluate.h" 13 | 14 | struct Value apply_single_value_func(struct Value *kwd_val, struct Execution_bundle *exec_bundle __attribute((unused)), struct Value *value) { 15 | struct String kwd = value_as_keyword(kwd_val); 16 | 17 | if(string_matches_heap(&kwd, &print_const)){ 18 | print(*value); 19 | printf("\n"); 20 | value->type = TYPE_UNDEF; 21 | value->data.bl = false; 22 | } else if(string_matches_heap(&kwd, &length_const)){ 23 | *value = value_from_long(length(*value)); 24 | } else if(string_matches_heap(&kwd, &return_const)){ 25 | return *value; 26 | } else if(string_matches_heap(&kwd, &eval_const)){ 27 | *value = eval(value, exec_bundle); 28 | } else if(string_matches_heap(&kwd, &read_line_const)){ 29 | *value = value_from_string(read_line(value)); 30 | } else if(string_matches_heap(&kwd, &read_file_const)){ 31 | *value = value_from_string(read_file(value_as_string(value))); 32 | } else if(string_matches_heap(&kwd, &import_const)){ 33 | huo_ast *old_ast = exec_bundle->ast; 34 | exec_bundle->ast = read_import(value_as_string(value)); 35 | *value = execute(exec_bundle); 36 | exec_bundle->ast = old_ast; 37 | } else if(string_concat_heap(&kwd, &typeof_const)){ 38 | *value = value_from_string(type_to_string(value->type)); 39 | } else { 40 | value->type = TYPE_UNDEF; 41 | value->data.bl = false; 42 | } 43 | return *value; 44 | } 45 | -------------------------------------------------------------------------------- /src/apply_single_value_func.h: -------------------------------------------------------------------------------- 1 | #ifndef _APPLY_SINGLE_VALUE_H 2 | #define _APPLY_SINGLE_VALUE_H 3 | 4 | struct Value apply_single_value_func(struct Value *kwd_val, struct Execution_bundle *exec_bundle, struct Value *value); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/base_util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "structures/structures.h" 8 | #include "base_util.h" 9 | #include "core_functions.h" 10 | #include "config.h" 11 | #include "process_defs.h" 12 | #include "constants.h" 13 | 14 | bool __size_t_mul_overflow(size_t a, size_t b, size_t *res) { 15 | #if defined(MUL_OVERFLOW) 16 | return MUL_OVERFLOW(a, b, res); 17 | #elif SIZE_MAX <= (UINTMAX_MAX / SIZE_MAX) 18 | uintmax_t res_long = (uintmax_t) a * (uintmax_t) b; 19 | if (res_long > SIZE_MAX) 20 | return true; 21 | *res = (size_t) res_long; 22 | return false; 23 | #elif defined(__UINT128__) 24 | if (sizeof(__UINT128__) >= sizeof(size_t) * 2) { 25 | __UINT128__ res_long = (__UINT128__) a * (__UINT128__) b; 26 | if (res_long > SIZE_MAX) 27 | return true; 28 | *res = (size_t) res_long; 29 | return false; 30 | } else { 31 | WARN_ONCE("size_t is HOW long?"); 32 | WARN_ONCE("Using slow but portable overflow test"); 33 | } 34 | #else 35 | #pragma message ("Using slow but portable overflow test") 36 | #endif 37 | //Slow but portable 38 | size_t res_short = a * b; 39 | if ((a != 0) && ((res_short / a) != b)) 40 | return true; 41 | *res = res_short; 42 | return false; 43 | } 44 | 45 | void *malloc_or_die(size_t size) { 46 | void *ptr = malloc(size); 47 | if (ptr == NULL) 48 | ERROR("Malloc error"); 49 | return ptr; 50 | } 51 | 52 | size_t arr_malloc_size(size_t num, size_t size) { 53 | size_t res; 54 | if (__size_t_mul_overflow(num, size, &res)) { 55 | ERROR("Overflow in array allocation!"); 56 | } 57 | return res; 58 | } 59 | 60 | char *o_strdup(const char *str) { 61 | size_t len = strlen(str); 62 | char *dup = ARR_MALLOC(len + 1, char); 63 | strcpy(dup, str); 64 | return dup; 65 | } 66 | 67 | hash_table *push_scope(struct Scopes * scopes){ 68 | RESIZE(scopes->scopes, scopes->size + 1); 69 | hash_table *h = hash_table_new(&string_hash_code_vv, &string_matches_vv); 70 | scopes->scopes[scopes->size] = h; 71 | scopes->size++; 72 | scopes->current++; 73 | return h; 74 | } 75 | 76 | void pop_scope(struct Scopes * scopes){ 77 | assert (scopes->size > 0); 78 | scopes->size -= 1; 79 | scopes->current -= 1; 80 | //hash_table_free(scopes->scopes[scopes->size]); 81 | RESIZE(scopes->scopes, scopes->size); 82 | } 83 | 84 | struct Value sub_vars(struct Value *v, struct Scopes *scopes, huo_depth_t max_depth) { 85 | if (max_depth <= 0) { 86 | ERROR("Max depth exceeded in computation"); 87 | } 88 | if (v->type == TYPE_ARRAY) { 89 | for (size_t i = 0; i < v->data.array->size; i++) { 90 | *(v->data.array->values[i]) = sub_vars(v->data.array->values[i], scopes, max_depth); 91 | } 92 | } else if (v->type == TYPE_KEYWORD) { 93 | struct Value *w = NULL; 94 | struct String kwd = value_as_keyword(v); 95 | if ((w = get_letted_value(scopes, kwd)) != NULL) { 96 | v = w; 97 | } else if (string_matches_heap(&kwd, &true_const)) { 98 | return value_from_bool(true); 99 | } else if (string_matches_heap(&kwd, &false_const)) { 100 | return value_from_bool(false); 101 | } else { 102 | ERROR("Undefined variable: %s", string_to_chars(&kwd)); 103 | } 104 | } 105 | return *v; 106 | } 107 | -------------------------------------------------------------------------------- /src/base_util.h: -------------------------------------------------------------------------------- 1 | #ifndef _BASE_UTIL_H 2 | #define _BASE_UTIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "structures/structures.h" 8 | #if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32) && !defined(__CYGWIN__) 9 | #include 10 | #endif 11 | #include 12 | #include "config.h" 13 | 14 | #define PASTE_HELPER(a,b) a ## b 15 | #define PASTE(a,b) PASTE_HELPER(a,b) 16 | 17 | #define WARN_ONCE(...) _WARN_ONCE(PASTE(warn_once_, __COUNTER__), __VA_ARGS__) 18 | #define _WARN_ONCE(UNIQ, ...) do {\ 19 | static bool UNIQ = false;\ 20 | if (!UNIQ) {\ 21 | UNIQ = true;\ 22 | fprintf(stderr, __VA_ARGS__);\ 23 | fprintf(stderr, "\n");\ 24 | }\ 25 | } while (0) 26 | 27 | #define ASSERT_NOREC(...) _ASSERT_NOREC(PASTE(warn_once_, __COUNTER__), __VA_ARGS__) 28 | 29 | #if defined(NDEBUG) 30 | #define _ASSERT_NOREC(UNIQ, ...) 31 | #else 32 | #define _ASSERT_NOREC(UNIQ, ...) do {\ 33 | static bool UNIQ = false;\ 34 | if (!UNIQ) {\ 35 | UNIQ = true;\ 36 | assert (__VA_ARGS__);\ 37 | UNIQ = false;\ 38 | }\ 39 | } while (0) 40 | #endif 41 | 42 | /* Macro because it makes printf errors easier to detect at compile time */ 43 | #define ERROR(...) ERROR_AT(__FILE__, __func__, __LINE__, __VA_ARGS__) 44 | #if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32) && !defined(__CYGWIN__) 45 | #define ERROR_AT(FILE, FUNC, LINE, ...) do {\ 46 | void * buffer[5];\ 47 | char ** strings;\ 48 | backtrace(buffer, 5);\ 49 | strings = backtrace_symbols(buffer, 5);\ 50 | for (int i = 0; i < 5; i++){\ 51 | printf ("%s\n", strings[i]);\ 52 | }\ 53 | fprintf(stderr, "Error at %s:%s:%i: ", FILE, FUNC, LINE);\ 54 | fprintf(stderr, __VA_ARGS__);\ 55 | fprintf(stderr, "\n");\ 56 | /*assert(false);*/\ 57 | exit(1);\ 58 | } while (0); 59 | #else 60 | #define ERROR_AT(FILE, FUNC, LINE, ...) do {\ 61 | fprintf(stderr, "Error at %s:%s:%i: ", FILE, FUNC, LINE);\ 62 | fprintf(stderr, __VA_ARGS__);\ 63 | fprintf(stderr, "\n");\ 64 | /*assert(false);*/\ 65 | exit(1);\ 66 | } while (0); 67 | #endif 68 | 69 | #define ARR_MALLOC(num_elem, elem_val) malloc_or_die(arr_malloc_size((num_elem), sizeof(elem_val))) 70 | 71 | // Would be a function, but then So. Much. Casting. 72 | #define RESIZE(ptr_to_arr, new_len) do {\ 73 | if ((new_len) == 0) {\ 74 | free((void *) ptr_to_arr);\ 75 | (ptr_to_arr) = NULL;\ 76 | } else {\ 77 | (ptr_to_arr) = realloc((void *) (ptr_to_arr), arr_malloc_size((new_len), sizeof((ptr_to_arr)[0])));\ 78 | if ((ptr_to_arr) == NULL) {\ 79 | ERROR("Malloc failure!");\ 80 | }\ 81 | }\ 82 | } while (0) 83 | 84 | void *malloc_or_die(size_t size); 85 | size_t arr_malloc_size(size_t num, size_t size); 86 | char *o_strdup(const char *str); 87 | hash_table *push_scope(struct Scopes * scopes); 88 | void pop_scope(struct Scopes * scopes); 89 | struct Value sub_vars(struct Value *v, struct Scopes *scopes, huo_depth_t max_depth); 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/config.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "config.h" 7 | #include "base_util.h" 8 | 9 | #undef malloc 10 | void *_check_malloc(size_t s) { 11 | static unsigned int i = 0; 12 | static char c = 'n'; 13 | if (i == 0) { 14 | if (scanf("%c%ui\n", &c, &i) <= 0) 15 | ERROR("?"); 16 | if (i == 0) 17 | ERROR("?"); 18 | } 19 | i -= 1; 20 | if (c == 'n') { 21 | return malloc(s); 22 | } else if (c == '+') { 23 | if (s > SIZE_MAX / 2 - 1) 24 | s = SIZE_MAX; 25 | else { 26 | s = s * 2 + 1; 27 | } 28 | return malloc(s); 29 | } else { 30 | return NULL; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #ifndef HUO_CONFIG_H 2 | #define HUO_CONFIG_H 1 3 | 4 | #include 5 | #include 6 | 7 | #define PRIhi PRId64 8 | #define PRIuhi PRIu64 9 | 10 | #define SCNhi SCNd64 11 | #define SCNuhi SCNu64 12 | 13 | typedef int64_t huo_int_t; 14 | typedef uint64_t huo_uint_t; 15 | typedef uint_fast16_t huo_depth_t; 16 | 17 | #if 0 18 | #define malloc(x) _check_malloc(x) 19 | #endif 20 | 21 | #if defined(__clang__) 22 | // Clang defines __gnuc__ ??? 23 | #define __UINT128__ unsigned __int128 24 | 25 | #if __has_builtin(__builtin_mul_overflow) 26 | #define MUL_OVERFLOW(a, b, res) __builtin_mul_overflow((a), (b), (res)) 27 | #elif __has_builtin(__builtin_umulll_overflow) && SIZE_MAX == ULLONG_MAX 28 | #define MUL_OVERFLOW(a, b, res) __builtin_umulll_overflow((unsigned long long) (a), (unsigned long long) (b), (unsigned long long *) (res)) 29 | #elif __has_builtin(__builtin_umull_overflow) && SIZE_MAX == ULONG_MAX 30 | #define MUL_OVERFLOW(a, b, res) __builtin_umull_overflow((unsigned long) (a), (unsigned long) (b), (unsigned long *) (res)) 31 | #elif __has_builtin(__builtin_umul_overflow) && SIZE_MAX == UINT_MAX 32 | #define MUL_OVERFLOW(a, b, res) __builtin_umul_overflow((unsigned int) (a), (unsigned int) (b), (unsigned int *) (res)) 33 | #endif 34 | 35 | #define HAS_STATIC_ASSERT __has_extension(c_static_assert) 36 | 37 | #elif defined(__GNUC__) 38 | 39 | #define __UINT128__ unsigned __int128 40 | 41 | #define MUL_OVERFLOW(a, b, res) __builtin_mul_overflow((a), (b), (res)) 42 | 43 | #define HAS_STATIC_ASSERT 1 44 | 45 | #endif 46 | 47 | 48 | 49 | #if HAS_STATIC_ASSERT 50 | 51 | #define STATIC_ASSERT(cond,msg) CTA2(cond, msg) 52 | #define CTA2(cond, msg) _Static_assert(cond,msg) 53 | 54 | #else 55 | 56 | #pragma message "Using fallback static assert" 57 | 58 | #define CTASTR2(pre,post) pre ## post 59 | #define CTASTR(pre,post) CTASTR2(pre,post) 60 | #define STATIC_ASSERT(cond,msg) \ 61 | typedef struct { int CTASTR(static_assertion_failed_,msg) : !!(cond); } \ 62 | CTASTR(static_assertion_failed_,__COUNTER__) 63 | 64 | #endif 65 | 66 | void *_check_malloc(size_t s); 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/constants.c: -------------------------------------------------------------------------------- 1 | #include "structures/structures.h" 2 | #include "constants.h" 3 | #include "base_util.h" 4 | #include "config.h" 5 | 6 | const huo_depth_t RECURSE_MAX = 250; 7 | const huo_int_t LOOP_MAX = -1; 8 | 9 | struct String functions = STR_NEW("*+-/!=<>|&"); 10 | 11 | struct String numbers = STR_NEW("-0123456789"); 12 | 13 | struct String letters = STR_NEW("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); 14 | 15 | struct String print_const = STR_NEW("print"); 16 | 17 | struct String concat_const = STR_NEW("cat"); 18 | 19 | struct String run_const = STR_NEW("run"); 20 | 21 | struct String ast_const = STR_NEW("ast"); 22 | 23 | struct String if_const = STR_NEW("if"); 24 | 25 | struct String def_const = STR_NEW("def"); 26 | 27 | struct String let_const = STR_NEW("let"); 28 | 29 | struct String length_const = STR_NEW("length"); 30 | 31 | struct String index_const = STR_NEW("index"); 32 | 33 | struct String push_const = STR_NEW("push"); 34 | 35 | struct String each_const = STR_NEW("each"); 36 | 37 | struct String map_const = STR_NEW("map"); 38 | 39 | struct String reduce_const = STR_NEW("reduce"); 40 | 41 | struct String set_const = STR_NEW("set"); 42 | 43 | struct String for_const = STR_NEW("for"); 44 | 45 | struct String do_const = STR_NEW("do"); 46 | 47 | struct String read_file_const = STR_NEW("read"); 48 | 49 | struct String import_const = STR_NEW("import"); 50 | 51 | struct String substring_const = STR_NEW("substring"); 52 | 53 | struct String split_const = STR_NEW("split"); 54 | 55 | struct String return_const = STR_NEW("return"); 56 | 57 | struct String parallel_const = STR_NEW("parallel"); 58 | 59 | struct String switch_const = STR_NEW("switch"); 60 | 61 | struct String default_const = STR_NEW("default"); 62 | 63 | struct String while_const = STR_NEW("while"); 64 | 65 | struct String eval_const = STR_NEW("eval"); 66 | 67 | struct String read_line_const = STR_NEW("readline"); 68 | 69 | struct String false_const = STR_NEW("false"); 70 | 71 | struct String true_const = STR_NEW("true"); 72 | 73 | struct String typeof_const = STR_NEW("typeof"); 74 | 75 | struct String function_names = STR_NEW("[if, read, let, set, each, for, do, switch, parallel, import, map, reduce, substring, while]"); 76 | 77 | struct String keyword_const = STR_NEW("keyword"); 78 | struct String number_const = STR_NEW("number"); 79 | struct String string_const = STR_NEW("string"); 80 | struct String boolean_const = STR_NEW("boolean"); 81 | struct String array_const = STR_NEW("array"); 82 | struct String undefined_const = STR_NEW("undefined"); 83 | 84 | const char open_parens_const = '('; 85 | const char close_parens_const = ')'; 86 | const char root_type_const = 'r'; 87 | const char quote_const = '"'; 88 | const char bracket_const = '['; 89 | const char end_bracket_const = ']'; 90 | const char dot_const = '.'; 91 | 92 | bool is_a_open_parens(char ch){ return ch == open_parens_const; } 93 | bool is_a_close_parens(char ch){ return ch == close_parens_const; } 94 | bool is_a_root_type(char ch){ return ch == root_type_const; } 95 | bool is_a_quote(char ch){ return ch == quote_const; } 96 | bool is_a_bracket(char ch){ return ch == bracket_const; } 97 | bool is_a_end_bracket(char ch){ return ch == end_bracket_const; } 98 | 99 | bool is_a_function(char ch){ 100 | return string_contains(ch, &functions); 101 | } 102 | -------------------------------------------------------------------------------- /src/constants.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONSTANTS_H 2 | #define _CONSTANTS_H 3 | 4 | #include 5 | #include "structures/string.h" 6 | #include "base_util.h" 7 | 8 | 9 | extern const huo_depth_t RECURSE_MAX; 10 | extern const huo_int_t LOOP_MAX; 11 | 12 | extern struct String functions; 13 | extern struct String print_const; 14 | extern struct String concat_const; 15 | extern struct String if_const; 16 | extern struct String def_const; 17 | extern struct String let_const; 18 | extern struct String length_const; 19 | extern struct String index_const; 20 | extern struct String push_const; 21 | extern struct String each_const; 22 | extern struct String map_const; 23 | extern struct String reduce_const; 24 | extern struct String set_const; 25 | extern struct String for_const; 26 | extern struct String do_const; 27 | extern struct String read_file_const; 28 | extern struct String import_const; 29 | extern struct String substring_const; 30 | extern struct String split_const; 31 | extern struct String return_const; 32 | extern struct String parallel_const; 33 | extern struct String switch_const; 34 | extern struct String default_const; 35 | extern struct String while_const; 36 | extern struct String eval_const; 37 | extern struct String read_line_const; 38 | extern struct String function_names; 39 | extern struct String false_const; 40 | extern struct String true_const; 41 | extern struct String typeof_const; 42 | extern struct String run_const; 43 | extern struct String ast_const; 44 | 45 | extern struct String keyword_const; 46 | extern struct String number_const; 47 | extern struct String string_const; 48 | extern struct String boolean_const; 49 | extern struct String array_const; 50 | extern struct String undefined_const; 51 | 52 | extern const char open_parens_const; 53 | extern const char close_parens_const; 54 | extern const char root_type_const; 55 | extern const char quote_const; 56 | extern const char bracket_const; 57 | extern const char end_bracket_const; 58 | extern const char dot_const; 59 | 60 | bool is_a_open_parens(char ch); 61 | bool is_a_close_parens(char ch); 62 | bool is_a_root_type(char ch); 63 | bool is_a_quote(char ch); 64 | bool is_a_function(char ch); 65 | bool is_a_bracket(char ch); 66 | bool is_a_end_bracket(char ch); 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/core_functions.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "structures/structures.h" 5 | #include "constants.h" 6 | #include "base_util.h" 7 | #include "core_functions.h" 8 | #include "config.h" 9 | 10 | void print(struct Value a){ 11 | if(a.type == TYPE_STRING){ 12 | struct String str = value_as_string(&a); 13 | printf("\"%s\"", string_to_chars(&str)); 14 | } 15 | else if(a.type == TYPE_KEYWORD){ 16 | struct String kwd = value_as_keyword(&a); 17 | printf("%s", string_to_chars(&kwd)); 18 | } 19 | else if(a.type == TYPE_LONG) { 20 | printf("%" PRIhi, value_as_long(&a)); 21 | } 22 | else if(a.type == TYPE_FLOAT) { 23 | printf("%f", value_as_float(&a)); 24 | } 25 | else if(a.type == TYPE_BOOL) { 26 | if (value_as_bool(&a)){ 27 | printf("True"); 28 | } 29 | else{ 30 | printf("False"); 31 | } 32 | } 33 | else if(a.type == TYPE_ARRAY) { 34 | printf("[ "); 35 | struct Value_array *arr = value_as_array(&a); 36 | for(size_t i = 0; i < arr->size; i++){ 37 | print(*arr->values[i]); 38 | if(i < arr->size-1){ 39 | printf(", "); 40 | } 41 | } 42 | printf(" ]"); 43 | } 44 | else if(a.type == TYPE_UNDEF) { 45 | printf("undefined"); 46 | } 47 | } 48 | 49 | struct Value add(struct Value a, struct Value b){ 50 | if(a.type == TYPE_LONG && b.type == TYPE_LONG){ 51 | return value_from_long(value_as_long(&a) + value_as_long(&b)); 52 | } 53 | else if(a.type == TYPE_FLOAT && b.type == TYPE_FLOAT){ 54 | return value_from_float(value_as_float(&a) + value_as_float(&b)); 55 | } 56 | else if(a.type == TYPE_FLOAT && b.type == TYPE_LONG){ 57 | return value_from_float(value_as_float(&a) + (float)value_as_long(&b)); 58 | } 59 | else if(a.type == TYPE_LONG && b.type == TYPE_FLOAT){ 60 | return value_from_float((float)value_as_long(&a) + value_as_float(&b)); 61 | } 62 | else { 63 | ERROR("Mismatched types for add: %d != %d", a.type, b.type); 64 | } 65 | } 66 | 67 | struct Value mul(struct Value a, struct Value b){ 68 | if(a.type == TYPE_LONG && b.type == TYPE_LONG){ 69 | return value_from_long(value_as_long(&a) * value_as_long(&b)); 70 | } 71 | else if(a.type == TYPE_FLOAT && b.type == TYPE_FLOAT){ 72 | return value_from_float(value_as_float(&a) * value_as_float(&b)); 73 | } 74 | else if(a.type == TYPE_FLOAT && b.type == TYPE_LONG){ 75 | return value_from_float(value_as_float(&a) * (float)value_as_long(&b)); 76 | } 77 | else if(a.type == TYPE_LONG && b.type == TYPE_FLOAT){ 78 | return value_from_float((float)value_as_long(&a) * value_as_float(&b)); 79 | } 80 | else { 81 | ERROR("Mismatched types for add: %d != %d", a.type, b.type); 82 | } 83 | } 84 | 85 | struct Value sub(struct Value a, struct Value b){ 86 | if(a.type == TYPE_LONG && b.type == TYPE_LONG){ 87 | return value_from_long(value_as_long(&a) - value_as_long(&b)); 88 | } 89 | else if(a.type == TYPE_FLOAT && b.type == TYPE_FLOAT){ 90 | return value_from_float(value_as_float(&a) - value_as_float(&b)); 91 | } 92 | else if(a.type == TYPE_FLOAT && b.type == TYPE_LONG){ 93 | return value_from_float(value_as_float(&a) - (float)value_as_long(&b)); 94 | } 95 | else if(a.type == TYPE_LONG && b.type == TYPE_FLOAT){ 96 | return value_from_float((float)value_as_long(&a) - value_as_float(&b)); 97 | } 98 | else { 99 | ERROR("Mismatched types for sub: %d != %d", a.type, b.type); 100 | } 101 | } 102 | 103 | struct Value divide(struct Value a, struct Value b) { 104 | if(a.type == TYPE_LONG && b.type == TYPE_LONG){ 105 | long bl = value_as_long(&b); 106 | if (bl == 0) { 107 | ERROR("Division by 0"); 108 | } 109 | return long_divide(value_as_long(&a), bl); 110 | } 111 | else if(a.type == TYPE_FLOAT && b.type == TYPE_FLOAT){ 112 | long bf = value_as_float(&b); 113 | if (bf == 0) { 114 | ERROR("Division by 0"); 115 | } 116 | return value_from_float(value_as_float(&a) / bf); 117 | } 118 | else if(a.type == TYPE_FLOAT && b.type == TYPE_LONG){ 119 | long bl = value_as_long(&b); 120 | if (bl == 0) { 121 | ERROR("Division by 0"); 122 | } 123 | return value_from_float(value_as_float(&a) / (float) bl); 124 | } 125 | else if(a.type == TYPE_LONG && b.type == TYPE_FLOAT){ 126 | long bf = value_as_float(&b); 127 | if (bf == 0) { 128 | ERROR("Division by 0"); 129 | } 130 | return value_from_float((float) value_as_long(&a) / bf); 131 | } 132 | else { 133 | ERROR("Mismatched types for divide: %d != %d", a.type, b.type); 134 | } 135 | } 136 | 137 | 138 | struct Value long_divide(huo_int_t a, huo_int_t b) { 139 | if (a % b == 0) { 140 | return value_from_long(a / b); 141 | } else { 142 | return value_from_float((float) a / (float) b); 143 | } 144 | } 145 | 146 | struct Value concat(struct Value a, struct Value b){ 147 | if (a.type == TYPE_STRING && b.type == TYPE_STRING) { 148 | return string_concat(value_as_string(&a), value_as_string(&b)); 149 | } else if (a.type == TYPE_ARRAY && b.type == TYPE_ARRAY) { 150 | return array_concat(value_as_array(&a), value_as_array(&b)); 151 | } else { 152 | ERROR("Tried to concat %c and %c", a.type, b.type); 153 | } 154 | } 155 | 156 | struct Value array_concat(struct Value_array *a, struct Value_array *b) { 157 | return value_from_array(array_concat_heap(a, b)); 158 | } 159 | struct Value string_concat(struct String a, struct String b) { 160 | return value_from_string(string_concat_stack(&a, &b)); 161 | } 162 | 163 | struct Value not(struct Value a, struct Value b){ 164 | if(a.type == TYPE_BOOL && b.type == TYPE_BOOL){ 165 | return value_from_bool(value_as_bool(&a) != value_as_bool(&b)); 166 | } 167 | else if(a.type == TYPE_FLOAT && b.type == TYPE_FLOAT){ 168 | return value_from_bool(value_as_float(&a) != value_as_float(&b)); 169 | } 170 | else if(a.type == TYPE_LONG && b.type == TYPE_LONG){ 171 | return value_from_bool(value_as_long(&a) != value_as_long(&b)); 172 | } 173 | else if(a.type == TYPE_STRING && b.type == TYPE_STRING){ 174 | return value_from_bool(!string_matches_stack(value_as_string(&a), value_as_string(&b))); 175 | } 176 | else if(a.type == TYPE_ARRAY && b.type == TYPE_ARRAY){ 177 | return value_from_bool(!array_matches(value_as_array(&a), value_as_array(&b))); 178 | } 179 | else { 180 | ERROR("Mismatched types: %d != %d", a.type, b.type); 181 | } 182 | } 183 | 184 | struct Value and(struct Value a, struct Value b){ 185 | if(a.type == TYPE_BOOL && b.type == TYPE_BOOL){ 186 | return value_from_bool(value_as_bool(&a) && value_as_bool(&b)); 187 | } else { 188 | ERROR("& operator only takes boolean values: %d | %d != 1", a.type, b.type); 189 | } 190 | } 191 | 192 | struct Value or(struct Value a, struct Value b){ 193 | if(a.type == TYPE_BOOL && b.type == TYPE_BOOL){ 194 | return value_from_bool(value_as_bool(&a) || value_as_bool(&b)); 195 | } else { 196 | ERROR("| operator only takes boolean values: %d | %d != 1", a.type, b.type); 197 | } 198 | } 199 | 200 | struct Value equals(struct Value a, struct Value b){ 201 | if(a.type == TYPE_BOOL && b.type == TYPE_BOOL){ 202 | return value_from_bool(value_as_bool(&a) == value_as_bool(&b)); 203 | } 204 | else if(a.type == TYPE_FLOAT && b.type == TYPE_FLOAT){ 205 | return value_from_bool(value_as_float(&a) == value_as_float(&b)); 206 | } 207 | else if(a.type == TYPE_LONG && b.type == TYPE_LONG){ 208 | return value_from_bool(value_as_long(&a) == value_as_long(&b)); 209 | } 210 | else if(a.type == TYPE_STRING && b.type == TYPE_STRING){ 211 | return value_from_bool(string_matches_stack(value_as_string(&a), value_as_string(&b))); 212 | } 213 | else if(a.type == TYPE_ARRAY && b.type == TYPE_ARRAY){ 214 | return value_from_bool(array_matches(value_as_array(&a), value_as_array(&b))); 215 | } 216 | else if(a.type == TYPE_FLOAT && b.type == TYPE_LONG){ 217 | return value_from_bool(value_as_float(&a) == (float)value_as_long(&b)); 218 | } 219 | else if(a.type == TYPE_LONG && b.type == TYPE_FLOAT){ 220 | return value_from_bool((float)value_as_long(&a) == value_as_float(&b)); 221 | } 222 | else { 223 | ERROR("Mismatched types: %d != %d", a.type, b.type); 224 | } 225 | } 226 | 227 | struct Value greater_than(struct Value a, struct Value b){ 228 | if(a.type == TYPE_BOOL && b.type == TYPE_BOOL){ 229 | return value_from_bool(value_as_bool(&a) > value_as_bool(&b)); 230 | } 231 | else if(a.type == TYPE_FLOAT && b.type == TYPE_FLOAT){ 232 | return value_from_bool(value_as_float(&a) > value_as_float(&b)); 233 | } 234 | else if(a.type == TYPE_LONG && b.type == TYPE_LONG){ 235 | return value_from_bool(value_as_long(&a) > value_as_long(&b)); 236 | } 237 | else { 238 | ERROR("Mismatched types: %d != %d", a.type, b.type); 239 | } 240 | } 241 | 242 | bool can_cast_to_size_t(huo_int_t i) { 243 | return i >= 0 && (huo_uint_t) i <= SIZE_MAX; 244 | } 245 | 246 | struct Value set(struct Value index_val, struct Value item, struct Value *to_set) { 247 | huo_int_t index = value_as_long(&index_val); 248 | if (!can_cast_to_size_t(index)) { 249 | unsigned long long size_max = SIZE_MAX; 250 | ERROR("Index out of range for set: should be 0 <= %" PRIhi " < %llu", index, size_max); 251 | } 252 | if (to_set->type == TYPE_ARRAY) { 253 | return value_from_array(array_set((size_t) index, item, value_as_array(to_set))); 254 | } else if (to_set->type == TYPE_STRING) { 255 | struct String set = string_set((size_t) index, value_as_string(&item), value_as_string(to_set)); 256 | return value_from_string(string_copy_stack(&set)); 257 | } else { 258 | ERROR("Set type invalid: ('%c' != [TYPE_ARRAY, TYPE_STRING])", to_set->type); 259 | } 260 | } 261 | 262 | struct Value_array *array_set(size_t index, struct Value item, struct Value_array *array) { 263 | 264 | 265 | // Have to copy before incrementing size or else 266 | // recursive copies segfault 267 | struct Value *val = value_copy_heap(&item); 268 | 269 | if (index >= array->size) { 270 | RESIZE(array->values, index + 1); 271 | struct Value undef = {.type=TYPE_UNDEF}; 272 | for (size_t i = array->size; i < index; i++) { 273 | array->values[i] = value_copy_heap(&undef); 274 | } 275 | array->size = index + 1; 276 | } 277 | array->values[index] = val; 278 | return array; 279 | } 280 | 281 | struct String string_set(size_t index, struct String item, struct String string){ 282 | char c = string_index(&item, 0); 283 | if (index == string_length(&string)) { 284 | struct String char_str = string_from_char(c); 285 | string_concat_to(&string, &char_str); 286 | } else if (index < string_length(&string)) { 287 | string.body[index] = c; 288 | } else { 289 | ERROR("Invalid index: %zu > %zu", index, string_length(&string)); 290 | } 291 | return string; 292 | } 293 | 294 | struct Value push(struct Value what, struct Value where) { 295 | if (where.type == TYPE_ARRAY) { 296 | return value_from_array(array_push(what, value_as_array(&where))); 297 | } else if (where.type == TYPE_STRING) { 298 | return value_from_string(string_push(value_as_string(&what), value_as_string(&where))); 299 | } else { 300 | ERROR("Push type invalid: ('%c' != [TYPE_ARRAY, TYPE_STRING])", where.type); 301 | } 302 | } 303 | 304 | struct Value_array *array_push(struct Value a, struct Value_array *array){ 305 | RESIZE(array->values, array->size + 1); 306 | array->values[array->size] = value_copy_heap(&a); 307 | array->size++; 308 | return array; 309 | } 310 | 311 | struct String string_push(struct String a, struct String str){ 312 | if (string_length(&a) != 1) { 313 | ERROR("Character does not have length 1"); 314 | } 315 | return string_concat_stack(&str, &a); 316 | } 317 | 318 | struct Value substring(struct Value start, struct Value end, struct Value what) { 319 | huo_int_t start_i = value_as_long(&start); 320 | huo_int_t end_i = value_as_long(&end); 321 | if (start_i < 0 || (huo_uint_t) start_i >= length(what)) { 322 | ERROR("Start index out of range for substring: should be 0 <= %" PRIhi " < %zu", start_i, length(what)); 323 | } 324 | if (end_i < 0 || (huo_uint_t) end_i >= length(what)) { 325 | ERROR("End index out of range for substring: should be 0 <= %" PRIhi " < %zu", end_i, length(what)); 326 | } 327 | 328 | return substring_ll((size_t) start_i, (size_t) end_i, what); 329 | } 330 | 331 | struct Value substring_ll(size_t start_i, size_t end_i, struct Value what) { 332 | //if (what.type == TYPE_ARRAY) { 333 | // return value_from_array(array_slice(start_i, end_i, value_as_array(&what))); 334 | //} else 335 | if (what.type == TYPE_STRING) { 336 | return value_from_string(string_substring(start_i, end_i, value_as_string(&what))); 337 | } else { 338 | ERROR("Substring type invalid: ('%c' != [TYPE_ARRAY, TYPE_STRING])", what.type); 339 | } 340 | } 341 | 342 | struct String string_substring(size_t start, size_t end, struct String str){ 343 | assert(string_is_sane(&str)); 344 | if (end > start) { 345 | struct String result = { 346 | .length = (end - start), 347 | .body = ARR_MALLOC(string_length(&str) + 1, char) 348 | }; 349 | for(size_t i = 0; i < result.length; i++){ 350 | result.body[i] = str.body[i + start]; 351 | } 352 | result.body[result.length] = 0; 353 | assert(string_is_sane(&result)); 354 | return result; 355 | } else { 356 | return string_from_chars(NULL); 357 | } 358 | } 359 | 360 | struct Value split(struct Value sep, struct Value what) { 361 | return string_split(value_as_string(&sep), value_as_string(&what)); 362 | } 363 | 364 | struct Value string_split(struct String sep, struct String what) { 365 | 366 | assert(string_is_sane(&sep)); 367 | assert(string_is_sane(&what)); 368 | 369 | size_t c = 0; 370 | for(size_t i = 0; i < what.length; i++){ 371 | if(sep.length == 0 || sep.body[0] == what.body[i]){ 372 | c += 1; 373 | } 374 | } 375 | 376 | if (c == SIZE_MAX) { 377 | ERROR("Cannot split string into more than size_t pieces"); 378 | } 379 | 380 | size_t *indexes = NULL; 381 | RESIZE(indexes, c); 382 | size_t d = 0; 383 | for(size_t i = 0; i < what.length; i++){ 384 | if(sep.length == 0 || sep.body[0] == what.body[i]){ 385 | indexes[d++] = i; 386 | } 387 | } 388 | assert (c == d); 389 | struct Value_array * array = malloc_or_die(sizeof(struct Value_array)); 390 | array->values = NULL; 391 | RESIZE(array->values, c + 1); 392 | array->size = 0; 393 | for(size_t l = 0; l <= c; l++){ 394 | size_t start = !l ? l : indexes[l-1] + 1; 395 | size_t end = (l < c) ? indexes[l] : what.length; 396 | 397 | struct Value item = value_from_string(string_substring(start, end, what)); 398 | 399 | array->values[array->size] = value_copy_heap(&item); 400 | array->size++; 401 | } 402 | return value_from_array(array); 403 | } 404 | 405 | 406 | struct Value value_index(struct Value index, struct Value list) { 407 | huo_int_t i = value_as_long(&index); 408 | if(list.type == TYPE_ARRAY){ 409 | struct Value_array *a = value_as_array(&list); 410 | if (i < 0) { 411 | ERROR("Negative index: %" PRIhi, i); 412 | } 413 | size_t len = a->size; 414 | if ((huo_uint_t) i >= len) { 415 | ERROR("Invalid index: %" PRIhi " (len %zu)", i, len); 416 | } 417 | return *a->values[i]; 418 | } 419 | else if(list.type == TYPE_STRING){ 420 | struct String s = value_as_string(&list); 421 | struct String indexed_char = string_from_char(string_index(&s, i)); 422 | return value_from_string(string_copy_stack(&indexed_char)); 423 | } else { 424 | ERROR("Index takes a string or array, but got '%c' != [TYPE_ARRAY|TYPE_STRING]).", list.type); 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /src/core_functions.h: -------------------------------------------------------------------------------- 1 | #ifndef _CORE_FUNCTIONS_H 2 | #define _CORE_FUNCTIONS_H 3 | 4 | #include "structures/structures.h" 5 | 6 | void print(struct Value a); 7 | 8 | struct Value add(struct Value a, struct Value b); 9 | struct Value array_add(struct Value_array *a, struct Value_array *b); 10 | 11 | struct Value mul(struct Value a, struct Value b); 12 | 13 | struct Value sub(struct Value a, struct Value b); 14 | struct Value array_sub(struct Value_array *a, struct Value_array *b); 15 | 16 | struct Value divide(struct Value a, struct Value b); 17 | struct Value long_divide(huo_int_t a, huo_int_t b); 18 | 19 | struct Value concat(struct Value a, struct Value b); 20 | struct Value array_concat(struct Value_array *a, struct Value_array *b); 21 | struct Value string_concat(struct String a, struct String b); 22 | 23 | struct Value not(struct Value a, struct Value b); 24 | struct Value equals(struct Value a, struct Value b); 25 | struct Value and(struct Value a, struct Value b); 26 | struct Value or(struct Value a, struct Value b); 27 | 28 | struct Value set(struct Value index, struct Value item, struct Value *to_set); 29 | struct Value_array *array_set(size_t index, struct Value item, struct Value_array *array); 30 | struct String string_set(size_t index, struct String item, struct String string); 31 | 32 | struct Value push(struct Value what, struct Value where); 33 | struct Value_array *array_push(struct Value a, struct Value_array *arr); 34 | struct String string_push(struct String a, struct String str); 35 | 36 | struct Value substring(struct Value start, struct Value end, struct Value what); 37 | struct Value substring_ll(size_t start_i, size_t end_i, struct Value what); 38 | //struct Value array_slice(size_t start, size_t end, struct Value_array what); 39 | struct String string_substring(size_t start, size_t end, struct String what); 40 | 41 | struct Value split(struct Value sep, struct Value what); 42 | struct Value string_split(struct String sep, struct String what); 43 | 44 | struct Value greater_than(struct Value a, struct Value b); 45 | 46 | struct Value value_index(struct Value index, struct Value v); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/execute.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "structures/structures.h" 4 | #include "core_functions.h" 5 | #include "base_util.h" 6 | #include "process_defs.h" 7 | #include "constants.h" 8 | #include "execute.h" 9 | #include "execution_functions/reduce_ast.h" 10 | #include "apply_core_function.h" 11 | #include "apply_execution_function.h" 12 | #include "apply_single_value_func.h" 13 | #include "config.h" 14 | 15 | struct Value execute(struct Execution_bundle * exec_bundle){ 16 | exec_bundle->max_depth -= 1; 17 | 18 | huo_ast * ast = exec_bundle->ast; 19 | //printf("EXE: %s\n", string_to_chars(ast_to_string(ast))); 20 | struct Scopes * scopes = exec_bundle->scopes; 21 | huo_depth_t max_depth = exec_bundle->max_depth; 22 | 23 | struct Value result; 24 | if (max_depth <= 0) { 25 | ERROR("Max depth exceeded in computation"); 26 | } 27 | if(ast_type(ast) == AST_ARRAY) { 28 | struct Value_array *arr = malloc_or_die(sizeof(struct Value_array)); 29 | arr->size = ast_size(ast); 30 | arr->values = ARR_MALLOC(arr->size, struct Value *); 31 | for (size_t i = 0; i < arr->size; i++) { 32 | 33 | exec_bundle->ast = ast_child(ast, i); 34 | struct Value v = execute(exec_bundle); 35 | exec_bundle->ast = ast; 36 | arr->values[i] = value_copy_heap(&v); 37 | } 38 | result = value_from_array(arr); 39 | } else if(!ast_size(ast)) { 40 | // ast has no children so must be a variable 41 | result = sub_vars(ast_value(ast), scopes, max_depth - 1); 42 | } else { 43 | huo_ast *func; 44 | struct Value *kwd = ast_value(ast_child(ast, 0)); 45 | bool is_unbound_kwd = (kwd->type == TYPE_KEYWORD); 46 | 47 | if(is_unbound_kwd && apply_execution_function(kwd, &result, exec_bundle)){ 48 | // if first item in ast node is a keyword and we can execute it we're done 49 | } 50 | else if(is_unbound_kwd && (func = get_defined_func(scopes, value_as_keyword(kwd))) != NULL) { 51 | // here the keyword points to a user defined function 52 | make_args_map(exec_bundle, func); 53 | 54 | exec_bundle->ast = ast_copy(get_defined_body(func)); 55 | result = execute(exec_bundle); 56 | scopes->current--; 57 | } 58 | else if(ast_size(ast) == 1){ 59 | 60 | exec_bundle->ast = ast_child(ast, 0); 61 | result = execute(exec_bundle); 62 | exec_bundle->ast = ast; 63 | } 64 | else if(is_unbound_kwd && ast_size(ast) == 2) { 65 | 66 | exec_bundle->ast = ast_child(ast, 1); 67 | // printf("'%s' = '", string_to_chars(ast_to_string(exec_bundle->ast))); 68 | struct Value a = execute(exec_bundle); 69 | 70 | exec_bundle->ast = ast; 71 | // print(a); 72 | // printf("'\n"); 73 | result = apply_single_value_func(kwd, exec_bundle, &a); 74 | } 75 | else if (is_unbound_kwd && ast_size(ast) == 3) { 76 | 77 | exec_bundle->ast = ast_child(ast, 1); 78 | struct Value a = execute(exec_bundle); 79 | 80 | exec_bundle->ast = ast_child(ast, 2); 81 | struct Value b = execute(exec_bundle); 82 | 83 | exec_bundle->ast = ast; 84 | 85 | result = apply_core_function(kwd, exec_bundle, &a, &b); 86 | } else { 87 | result = reduce_ast(exec_bundle); 88 | } 89 | } 90 | 91 | exec_bundle->max_depth += 1; 92 | return result; 93 | } 94 | -------------------------------------------------------------------------------- /src/execute.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXECUTE_H 2 | #define _EXECUTE_H 3 | 4 | #include "structures/structures.h" 5 | 6 | struct Value reduce(huo_ast * ast, hash_table *defined, struct Scopes * scopes); 7 | struct Value execute(struct Execution_bundle * exec_bundle); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/execution_functions/evaluate.c: -------------------------------------------------------------------------------- 1 | #include "../structures/structures.h" 2 | #include "../constants.h" 3 | #include "../tokenizer.h" 4 | #include "../parser.h" 5 | #include "../store_defs.h" 6 | #include "../execute.h" 7 | #include "../core_functions.h" 8 | #include "../config.h" 9 | 10 | struct Value eval(struct Value *string, struct Execution_bundle * exec_bundle) { 11 | 12 | struct Value result; 13 | struct Tokens t = { 14 | .length = 0, 15 | .counter = 0 16 | }; 17 | struct Tokens * tokens = tokenize(value_as_string(string), &t); 18 | huo_ast *root = parse(tokens); 19 | huo_ast *ast = exec_bundle->ast; 20 | for(size_t i = 0; i < ast_size(root); i++) { 21 | exec_bundle->ast = ast_child(root, i); 22 | result = execute(exec_bundle); 23 | } 24 | exec_bundle->ast = ast; 25 | return result; 26 | } 27 | -------------------------------------------------------------------------------- /src/execution_functions/evaluate.h: -------------------------------------------------------------------------------- 1 | #ifndef _EVALUATE_H 2 | #define _EVALUATE_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | struct Value eval(struct Value * string, struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/execution_functions/for_each.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../structures/structures.h" 3 | #include "../execute.h" 4 | #include "../base_util.h" 5 | #include "../core_functions.h" 6 | #include "let_binding.h" 7 | #include "for_each.h" 8 | #include "../config.h" 9 | 10 | struct Value for_each(struct Execution_bundle * exec_bundle) { 11 | huo_ast * ast = exec_bundle->ast; 12 | struct Scopes * scopes = exec_bundle->scopes; 13 | 14 | if (exec_bundle->max_depth <= 0) { 15 | ERROR("Max depth exceeded in computation"); 16 | } 17 | bool use_index; 18 | size_t func_index; 19 | if (ast_size(ast) == 5) { 20 | use_index = true; 21 | func_index = 4; 22 | } else if (ast_size(ast) == 4) { 23 | use_index = false; 24 | func_index = 3; 25 | } else { 26 | ERROR("Wrong number of arguments for for_each: %zu != [5,4]\n", ast_size(ast)); 27 | } 28 | 29 | exec_bundle->ast = ast_child(ast, 1); 30 | struct Value array = execute(exec_bundle); 31 | 32 | exec_bundle->ast = ast; 33 | if(array.type == TYPE_STRING){ 34 | return for_each_string(value_as_string(&array), exec_bundle); 35 | } else if (array.type == TYPE_ARRAY) { 36 | for(size_t i = 0; i < array.data.array->size; i++){ 37 | struct Value *item = array.data.array->values[i]; 38 | huo_ast * function = ast_copy(ast_child(ast, func_index)); 39 | store_let_value(ast_value(ast_child(ast, 2)), item, scopes); 40 | if (use_index) { 41 | struct Value index = value_from_long(i); 42 | store_let_value(ast_value(ast_child(ast, 3)), &index, scopes); 43 | } 44 | exec_bundle->ast = function; 45 | execute(exec_bundle); 46 | } 47 | exec_bundle->ast = ast; 48 | return array; 49 | } else { 50 | ERROR("Invalid type for for_each iterable: '%c' != TYPE_ARRAY", array.type); 51 | } 52 | } 53 | 54 | struct Value for_each_string(struct String string, struct Execution_bundle * exec_bundle){ 55 | huo_ast * ast = exec_bundle->ast; 56 | struct Scopes * scopes = exec_bundle->scopes; 57 | 58 | bool use_index; 59 | size_t func_index; 60 | if (ast_size(ast) == 5) { 61 | use_index = true; 62 | func_index = 4; 63 | } else if (ast_size(ast) == 4) { 64 | use_index = false; 65 | func_index = 3; 66 | } else { 67 | ERROR("Wrong number of arguments for for_each: %zu != [5,4]\n", ast_size(ast)); 68 | } 69 | 70 | for(size_t i = 0; i < string.length; i++){ 71 | struct String item = string_substring(i, i+1, string); 72 | struct Value item_val = value_from_string(string_copy_stack(&item)); 73 | huo_ast * function = ast_copy(ast_child(ast, func_index)); 74 | store_let_value(ast_value(ast_child(ast, 2)), &item_val, scopes); 75 | if (use_index) { 76 | struct Value index = value_from_long(i); 77 | store_let_value(ast_value(ast_child(ast, 3)), &index, scopes); 78 | } 79 | exec_bundle->ast = function; 80 | execute(exec_bundle); 81 | } 82 | exec_bundle->ast = ast; 83 | return value_from_string(string); 84 | } 85 | -------------------------------------------------------------------------------- /src/execution_functions/for_each.h: -------------------------------------------------------------------------------- 1 | #ifndef _FOR_EACH_H 2 | #define _FOR_EACH_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | struct Value for_each(struct Execution_bundle * exec_bundle); 7 | struct Value for_each_string(struct String string, struct Execution_bundle * exec_bundle); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/execution_functions/for_loop.c: -------------------------------------------------------------------------------- 1 | #include "../structures/structures.h" 2 | #include "../execute.h" 3 | #include "../base_util.h" 4 | #include "../config.h" 5 | 6 | void for_loop(struct Execution_bundle *exec_bundle){ 7 | huo_ast * ast = exec_bundle->ast; 8 | if (exec_bundle->max_depth <= 0) { 9 | ERROR("Max depth exceeded in computation"); 10 | } 11 | if (ast_size(ast) != 4) { 12 | ERROR("Wrong number of arguments for for_loop: %zu != 4\n", ast_size(ast)); 13 | } 14 | exec_bundle->ast = ast_child(ast, 1); 15 | struct Value start = execute(exec_bundle); 16 | 17 | exec_bundle->ast = ast_child(ast, 2); 18 | struct Value end = execute(exec_bundle); 19 | 20 | huo_int_t start_i = value_as_long(&start); 21 | huo_int_t end_i = value_as_long(&end); 22 | 23 | if(start_i > end_i){ 24 | for(huo_int_t i = start_i; i > end_i; i--){ 25 | 26 | exec_bundle->ast = ast_copy(ast_child(ast, 3)); 27 | execute(exec_bundle); 28 | } 29 | } else { 30 | for(huo_int_t i = start_i; i < end_i; i++){ 31 | 32 | exec_bundle->ast = ast_copy(ast_child(ast, 3)); 33 | execute(exec_bundle); 34 | } 35 | } 36 | exec_bundle->ast = ast; 37 | } 38 | -------------------------------------------------------------------------------- /src/execution_functions/for_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef _FOR_LOOP_H 2 | #define _FOR_LOOP_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | void for_loop(struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/execution_functions/if_block.c: -------------------------------------------------------------------------------- 1 | #include "../structures/structures.h" 2 | #include "../execute.h" 3 | #include "../base_util.h" 4 | #include "../config.h" 5 | 6 | struct Value if_block(struct Execution_bundle * exec_bundle){ 7 | huo_ast * ast = exec_bundle->ast; 8 | if (exec_bundle->max_depth <= 0) { 9 | ERROR("Max depth exceeded in computation"); 10 | } 11 | if (ast_size(ast) != 3 && ast_size(ast) != 4) { 12 | ERROR("Wrong number of arguments for if_block: %zu != [3,4]\n", ast_size(ast)); 13 | } 14 | exec_bundle->ast = ast_child(ast, 1); 15 | struct Value result = execute(exec_bundle); 16 | if(value_as_bool(&result)){ // result is boolean true 17 | exec_bundle->ast = ast_child(ast, 2); 18 | result = execute(exec_bundle); 19 | } 20 | else if (ast_size(ast) == 4) { // result is boolean false 21 | exec_bundle->ast = ast_child(ast, 3); 22 | result = execute(exec_bundle); 23 | } else { 24 | result = value_from_undef(); 25 | } 26 | exec_bundle->ast = ast; 27 | return result; 28 | } 29 | -------------------------------------------------------------------------------- /src/execution_functions/if_block.h: -------------------------------------------------------------------------------- 1 | #ifndef _IF_BLOCK_H 2 | #define _IF_BLOCK_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | struct Value if_block(struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/execution_functions/let_binding.c: -------------------------------------------------------------------------------- 1 | #include "../structures/structures.h" 2 | #include "../execute.h" 3 | #include "../base_util.h" 4 | #include "../core_functions.h" 5 | #include "../config.h" 6 | 7 | void store_let_value(struct Value * key, struct Value * value, struct Scopes * scopes){ 8 | 9 | hash_table *let_store = scopes->scopes[scopes->current]; 10 | struct definition *def = malloc_or_die(sizeof(struct definition)); 11 | def->is_func = false; 12 | def->val.val = value_copy_heap(value); 13 | struct String val = value_as_keyword(key); 14 | //printf("val=%s --> ", string_to_chars(&val)); 15 | //print(*value); 16 | //printf("\n"); 17 | if (hash_table_put(let_store, string_copy_heap(&val), def)) { 18 | // Overriding 19 | } else { 20 | // New addition 21 | } 22 | } 23 | void store_def_func(struct Value * key, huo_ast *func, struct Scopes * scopes){ 24 | hash_table *let_store = scopes->scopes[scopes->current]; 25 | struct definition *def = malloc_or_die(sizeof(struct definition)); 26 | def->is_func = true; 27 | def->val.ast = func; 28 | struct String val = value_as_keyword(key); 29 | if (hash_table_put(let_store, string_copy_heap(&val), def)) { 30 | // Overriding 31 | } else { 32 | // New addition 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/execution_functions/let_binding.h: -------------------------------------------------------------------------------- 1 | #ifndef _LET_BINDING_H 2 | #define _LET_BINDING_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | void store_let_value(struct Value * key, struct Value * value, struct Scopes * scopes); 7 | void store_def_func(struct Value * key, huo_ast *func, struct Scopes * scopes); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/execution_functions/map_array.c: -------------------------------------------------------------------------------- 1 | #include "../structures/structures.h" 2 | #include "../execute.h" 3 | #include "../base_util.h" 4 | #include "let_binding.h" 5 | #include "../config.h" 6 | 7 | struct Value map_array(struct Execution_bundle * exec_bundle){ 8 | huo_ast * ast = exec_bundle->ast; 9 | if (exec_bundle->max_depth <= 0) { 10 | ERROR("Max depth exceeded in computation"); 11 | } 12 | bool use_index; 13 | size_t func_index; 14 | if (ast_size(ast) == 5) { 15 | use_index = true; 16 | func_index = 4; 17 | } else if (ast_size(ast) == 4) { 18 | use_index = false; 19 | func_index = 3; 20 | } else { 21 | ERROR("Wrong number of arguments for map_array: %zu != [4,5]\n", ast_size(ast)); 22 | } 23 | exec_bundle->ast = ast_child(ast, 1); 24 | struct Value array = execute(exec_bundle); 25 | if (array.type != TYPE_ARRAY) { 26 | ERROR("Wrong type for map: '%c' != TYPE_ARRAY", array.type); 27 | } 28 | for(size_t i = 0; i < array.data.array->size; i++){ 29 | struct Value *item = value_copy_heap(array.data.array->values[i]); 30 | huo_ast * function = ast_copy(ast_child(ast, func_index)); 31 | store_let_value(ast_value(ast_child(ast, 2)), item, exec_bundle->scopes); 32 | if (use_index) { 33 | struct Value index = value_from_long(i); 34 | store_let_value(ast_value(ast_child(ast, 3)), &index, exec_bundle->scopes); 35 | } 36 | exec_bundle->ast = function; 37 | struct Value result = execute(exec_bundle); 38 | array.data.array->values[i] = value_copy_heap(&result); 39 | } 40 | exec_bundle->ast = ast; 41 | return array; 42 | } 43 | -------------------------------------------------------------------------------- /src/execution_functions/map_array.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAP_ARRAY_H 2 | #define _MAP_ARRAY_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | struct Value map_array(struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/execution_functions/parallel_execution.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../structures/structures.h" 4 | #include "../execute.h" 5 | #include "../base_util.h" 6 | #include "../config.h" 7 | 8 | void * parallel_routine(void * bundle_ptr){ 9 | struct Execution_bundle * bundle = (struct Execution_bundle *) bundle_ptr; 10 | if (bundle->max_depth <= 0) { 11 | ERROR("Max depth exceeded in computation"); 12 | } 13 | execute(bundle); 14 | return NULL; 15 | } 16 | 17 | #if 0 18 | void parallel_execution(struct Execution_bundle * exec_bundle){ 19 | if (exec_bundle->max_depth <= 0) { 20 | ERROR("Max depth exceeded in computation"); 21 | } 22 | size_t num_children = ast_size(ast); 23 | pthread_t *tid = ARR_MALLOC(num_children, pthread_t); 24 | struct Execution_bundle * bundle = ARR_MALLOC(num_children, struct Execution_bundle); 25 | for(size_t i = 0; i < num_children; i++){ 26 | bundle[i].ast=exec_bundle->ast_child(ast, i); 27 | bundle[i].defined=exec_bundle->defined; // BUG: defined is NOT threadsafe. Needs to be copied. 28 | bundle[i].scopes=exec_bundle->scopes; // BUG: scopes is NOT threadsafe. Needs to be copied. 29 | bundle[i].function_names=exec_bundle->function_names; 30 | bundle[i].max_depth = exec_bundle->max_depth - 1; 31 | pthread_create(&tid[i], NULL, ¶llel_routine, &bundle[i]); 32 | } 33 | for (size_t j = 0; j < num_children; j++){ 34 | pthread_join(tid[j], NULL); 35 | } 36 | free(bundle); 37 | } 38 | #else 39 | // Dummy single-threaded version. 40 | void parallel_execution(struct Execution_bundle * exec_bundle){ 41 | if (exec_bundle->max_depth <= 0) { 42 | ERROR("Max depth exceeded in computation"); 43 | } 44 | huo_ast * ast = exec_bundle->ast; 45 | for(size_t i = 1; i < ast_size(ast); i++){ 46 | exec_bundle->ast = ast_child(ast, i); 47 | parallel_routine(exec_bundle); 48 | } 49 | exec_bundle->ast = ast; 50 | } 51 | #endif 52 | -------------------------------------------------------------------------------- /src/execution_functions/parallel_execution.h: -------------------------------------------------------------------------------- 1 | #ifndef _PARALLEL_EXECUTION_H 2 | #define _PARALLEL_EXECUTION_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | void parallel_execution(struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/execution_functions/read_file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../structures/structures.h" 3 | #include "../execute.h" 4 | #include "../base_util.h" 5 | #include "../config.h" 6 | 7 | bool read_file_to(struct String *file_contents, const char *filename) { 8 | //TODO: make robust if file is longer than size_t characters. 9 | 10 | FILE *fp; 11 | fp = fopen(filename, "r"); 12 | if(fp == NULL){ 13 | return false; 14 | } 15 | char c; 16 | while ((c = fgetc(fp)) != EOF){ 17 | if (c == 0) { 18 | ERROR("Null byte in input file"); 19 | } else { 20 | RESIZE(file_contents->body, file_contents->length + 1); 21 | file_contents->body[file_contents->length] = c; 22 | file_contents->length++; 23 | } 24 | } 25 | fclose(fp); 26 | 27 | // Null character at end 28 | RESIZE(file_contents->body, file_contents->length + 1); 29 | file_contents->body[file_contents->length] = 0; 30 | 31 | assert(string_is_sane(file_contents)); 32 | return true; 33 | } 34 | 35 | struct String read_file(struct String file_name){ 36 | struct String file = string_from_chars(NULL); 37 | char *s = string_to_chars(&file_name); 38 | if (!read_file_to(&file, s)) { 39 | ERROR("Cannot find file: \"%s\"", s); 40 | } 41 | return file; 42 | } 43 | -------------------------------------------------------------------------------- /src/execution_functions/read_file.h: -------------------------------------------------------------------------------- 1 | #ifndef _READ_FILE_H 2 | #define _READ_FILE_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | bool read_file_to(struct String *file_contents, const char *filename); 7 | struct String read_file(struct String); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/execution_functions/read_line.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../structures/structures.h" 3 | #include "../structures/string.h" 4 | #include "../structures/value.h" 5 | #include "../constants.h" 6 | #include "../execute.h" 7 | #include "../core_functions.h" 8 | #include "../config.h" 9 | 10 | struct String read_line(struct Value * string){ 11 | //TODO: make robust if line is >= size_t characters. 12 | 13 | // read line takes a string to display as prompt 14 | // but displays it without quotes 15 | string->type = TYPE_KEYWORD; 16 | print(*string); 17 | string->type = TYPE_STRING; 18 | 19 | struct String input = { 20 | .length = 0, 21 | .body = NULL 22 | }; 23 | 24 | char c; 25 | while ((c = getchar()) != '\n' && c != EOF){ 26 | if (c == 0) { 27 | ERROR("Null byte in input file"); 28 | } else if(c != '\n'){ 29 | RESIZE(input.body, input.length + 1); 30 | input.body[input.length] = c; 31 | input.length++; 32 | } 33 | } 34 | if (input.length == 0) { 35 | ERROR("Input closed"); 36 | } 37 | RESIZE(input.body, input.length + 1); 38 | input.body[input.length] = 0; 39 | 40 | assert(string_is_sane(&input)); 41 | 42 | return input; 43 | } 44 | -------------------------------------------------------------------------------- /src/execution_functions/read_line.h: -------------------------------------------------------------------------------- 1 | #ifndef _READ_LINE_H 2 | #define _READ_LINE_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | struct String read_line(struct Value * string); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/execution_functions/reduce.c: -------------------------------------------------------------------------------- 1 | #include "../structures/structures.h" 2 | #include "../execute.h" 3 | #include "../base_util.h" 4 | #include "let_binding.h" 5 | #include "../core_functions.h" 6 | #include "../config.h" 7 | 8 | struct Value reduce_array(struct Execution_bundle * exec_bundle){ 9 | huo_ast * ast = exec_bundle->ast; 10 | if (exec_bundle->max_depth <= 0) { 11 | ERROR("Max depth exceeded in computation"); 12 | } 13 | if (ast_size(ast) != 5 && ast_size(ast) != 6) { 14 | ERROR("Wrong number of arguments for reduce_array: %zu != [5, 6]\n", ast_size(ast)); 15 | } 16 | if (ast_type(ast_child(ast, 2)) != AST_KEYWORD) { 17 | ERROR("Invalid type for reduce_array: '%c' != 'k'\n", ast_type(ast_child(ast, 2))); 18 | } 19 | if (ast_type(ast_child(ast, 3)) != AST_KEYWORD) { 20 | ERROR("Invalid type for reduce_array: '%c' != 'k'\n", ast_type(ast_child(ast, 3))); 21 | } 22 | size_t start; 23 | struct Value result; 24 | exec_bundle->ast = ast_child(ast, 1); 25 | struct Value array = execute(exec_bundle); 26 | if (array.type != TYPE_ARRAY) { 27 | ERROR("Invalid type for reduce_array: '%c' != TYPE_ARRAY\n", array.type); 28 | } 29 | if (array.data.array->size <= 0) { 30 | return value_copy_stack(&array); 31 | } 32 | if(ast_size(ast) == 6){ 33 | exec_bundle->ast = ast_child(ast, 5); 34 | result = execute(exec_bundle); 35 | start = 0; 36 | } else { 37 | result = *array.data.array->values[0]; 38 | start = 1; 39 | } 40 | for(size_t i = start; i < array.data.array->size; i++){ 41 | struct Value * item = array.data.array->values[i]; 42 | huo_ast * function = ast_copy(ast_child(ast, 4)); 43 | store_let_value(ast_value(ast_child(ast, 2)), &result, exec_bundle->scopes); 44 | store_let_value(ast_value(ast_child(ast, 3)), item, exec_bundle->scopes); 45 | exec_bundle->ast = function; 46 | result = execute(exec_bundle); 47 | } 48 | exec_bundle->ast = ast; 49 | return result; 50 | } 51 | -------------------------------------------------------------------------------- /src/execution_functions/reduce.h: -------------------------------------------------------------------------------- 1 | #ifndef _REDUCE_H 2 | #define _REDUCE_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | struct Value reduce_array(struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/execution_functions/reduce_ast.c: -------------------------------------------------------------------------------- 1 | #include "../structures/structures.h" 2 | #include "../execute.h" 3 | #include "../base_util.h" 4 | #include "../config.h" 5 | 6 | struct Value reduce_ast(struct Execution_bundle * exec_bundle){ 7 | huo_ast * ast = exec_bundle->ast; 8 | if (exec_bundle->max_depth <= 0) { 9 | ERROR("Max depth exceeded in computation"); 10 | } 11 | if (ast_size(ast) < 1) { 12 | ERROR("Not enough arguments for reduce_ast: %zu < 2\n", ast_size(ast)); 13 | } 14 | struct Value result; 15 | 16 | for(size_t i = 0; i < ast_size(ast); i++){ 17 | exec_bundle->ast = ast_child(ast, i); 18 | result = execute(exec_bundle); 19 | } 20 | exec_bundle->ast = ast; 21 | return result; 22 | } 23 | -------------------------------------------------------------------------------- /src/execution_functions/reduce_ast.h: -------------------------------------------------------------------------------- 1 | #ifndef _REDUCE_AST_H 2 | #define _REDUCE_AST_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | struct Value reduce_ast(struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/execution_functions/switch.c: -------------------------------------------------------------------------------- 1 | #include "../structures/structures.h" 2 | #include "../constants.h" 3 | #include "../execute.h" 4 | #include "../base_util.h" 5 | #include "../core_functions.h" 6 | #include "../config.h" 7 | 8 | struct Value switch_case(struct Execution_bundle * exec_bundle){ 9 | huo_ast * ast = exec_bundle->ast; 10 | if (exec_bundle->max_depth <= 0) { 11 | ERROR("Max depth exceeded in computation"); 12 | } 13 | for(size_t i = 2; i < ast_size(ast); i++){ 14 | huo_ast * routine = ast_child(ast, i); 15 | if(ast_value(ast_child(routine, 0))->type == TYPE_KEYWORD && string_matches_heap(&default_const, &ast_value(ast_child(routine, 0))->data.str)) { 16 | if (i != ast_size(ast) - 1) { 17 | ERROR("Default not last case!"); 18 | } 19 | exec_bundle->ast = ast_child(routine, 1); 20 | struct Value ret = execute(exec_bundle); 21 | exec_bundle->ast = ast; 22 | return ret; 23 | } 24 | if (ast_size(routine) != 3) { 25 | ERROR("Invalid syntax for switch_case: %zu != 3", ast_size(routine)); 26 | } 27 | huo_ast * return_value = ast_child(routine, 2); 28 | ast_set_child(routine, 2, ast_child(ast, 1)); 29 | exec_bundle->ast = routine; 30 | struct Value result = execute(exec_bundle); 31 | if(value_as_bool(&result)){ 32 | exec_bundle->ast = return_value; 33 | struct Value ret = execute(exec_bundle); 34 | exec_bundle->ast = ast; 35 | return ret; 36 | } 37 | } 38 | exec_bundle->ast = ast; 39 | struct Value result; 40 | result.type = TYPE_UNDEF; 41 | return result; 42 | } 43 | -------------------------------------------------------------------------------- /src/execution_functions/switch.h: -------------------------------------------------------------------------------- 1 | #ifndef _SWITCH_H 2 | #define _SWITCH_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | struct Value switch_case(struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/execution_functions/while_loop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../structures/structures.h" 3 | #include "../constants.h" 4 | #include "../execute.h" 5 | #include "../base_util.h" 6 | #include "../config.h" 7 | 8 | void while_loop(struct Execution_bundle * exec_bundle){ 9 | huo_ast * ast = exec_bundle->ast; 10 | if(ast_size(ast) != 3){ 11 | ERROR("Not enough arguments for while: %zu < 3\n", ast_size(ast)); 12 | } 13 | huo_int_t i = 0; 14 | while (true) { 15 | if (LOOP_MAX != (huo_int_t) -1) { 16 | if (i++ >= LOOP_MAX) { 17 | break; 18 | } 19 | } 20 | exec_bundle->ast = ast_child(ast, 1); 21 | struct Value condition = execute(exec_bundle); 22 | if(value_as_bool(&condition)){ 23 | exec_bundle->ast = ast_child(ast, 2); 24 | execute(exec_bundle); 25 | } else { 26 | exec_bundle->ast = ast; 27 | return; 28 | } 29 | } 30 | ERROR("Max loops exceeded"); 31 | } 32 | -------------------------------------------------------------------------------- /src/execution_functions/while_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef _WHILE_LOOP_H 2 | #define _WHILE_LOOP_H 3 | 4 | #include "../structures/structures.h" 5 | 6 | void while_loop(struct Execution_bundle * exec_bundle); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/huo.c: -------------------------------------------------------------------------------- 1 | #define _DEFAULT_SOURCE 1 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "constants.h" 11 | #include "tokenizer.h" 12 | #include "parser.h" 13 | #include "structures/structures.h" 14 | #include "execution_functions/read_file.h" 15 | #include "execute.h" 16 | #include "store_defs.h" 17 | #include "base_util.h" 18 | #include "path_utils.h" 19 | #include "huo.h" 20 | #include "config.h" 21 | #include "core_functions.h" 22 | 23 | int main(int argc, char const *argv[]) { 24 | bool help_flag = false; 25 | bool command_flag = false; 26 | bool error_flag = false; 27 | bool file_flag = false; 28 | 29 | struct String to_execute = { 30 | .length = 0, 31 | .body = NULL 32 | }; 33 | 34 | // This is a little "brittle", but it works for now 35 | for (int i = 1; i < argc; i++) { 36 | if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { 37 | help_flag = true; 38 | } else if (!strcmp(argv[i], "-c")) { 39 | if (i == argc - 1) { 40 | fprintf(stderr, "Argument expected for %s option\n", argv[i]); 41 | error_flag = true; 42 | } else if (command_flag == true) { 43 | fprintf(stderr, "Multiple commands specified\n"); 44 | error_flag = true; 45 | } else { 46 | command_flag = true; 47 | to_execute = string_from_chars(argv[++i]); 48 | } 49 | } else if (i == argc - 1 && !file_flag) { 50 | file_flag = true; 51 | if (!read_file_to(&to_execute, argv[i])) { 52 | ERROR("Error opening file: %d (%s)", errno, strerror(errno)); 53 | } 54 | } else { 55 | fprintf(stderr, "Unknown option: %s\n", argv[i]); 56 | help_flag = true; 57 | error_flag = true; 58 | } 59 | if (error_flag) { 60 | break; 61 | } 62 | } 63 | if (command_flag && file_flag) { 64 | fprintf(stderr, "Command passed in but file also specified\n"); 65 | error_flag = true; 66 | } 67 | 68 | if (!command_flag && !file_flag && !help_flag) { 69 | assert (argc >= 1); 70 | 71 | char *path_to_exe = get_exe_path(argv[0]); 72 | 73 | char *path_to_exe_dir = get_path_dir(path_to_exe); 74 | 75 | char *path_to_repl = path_merge(path_to_exe_dir, "repl.huo"); 76 | 77 | // printf("%s \n", path_to_exe_dir); 78 | 79 | file_flag = true; 80 | 81 | if (!read_file_to(&to_execute, path_to_repl)) { 82 | ERROR("Error opening repl.huo: %d (%s)", errno, strerror(errno)); 83 | } 84 | 85 | free(path_to_repl); 86 | free(path_to_exe_dir); 87 | free(path_to_exe); 88 | } 89 | 90 | if (help_flag || error_flag) { 91 | fprintf(stderr, 92 | "usage: huo [FILE | -c cmd | -h | --help]\n" 93 | "Arguments:\n" 94 | "-c cmd program passed in as string\n" 95 | "FILE program read in as file\n" 96 | "-h, --help print this help message and exit\n"); 97 | return error_flag ? 1 : 0; // Redundant for now, but reminder to maybe return a different error code later 98 | } 99 | 100 | struct Tokens t = { 101 | .tokens = NULL, 102 | .length = 0, 103 | .counter = 0 104 | }; 105 | 106 | struct Tokens * tokens = tokenize(to_execute, &t); 107 | //for(size_t i = 0; i < tokens->length; i++){ 108 | // printf("%c", tokens->tokens[i].type); 109 | // } 110 | 111 | 112 | huo_ast *root = parse(tokens); 113 | 114 | // this prints the AST for reference 115 | //printf("%s\n", string_to_chars(ast_to_string(root))); 116 | 117 | struct Execution_bundle * exec_bundle = malloc_or_die(sizeof(struct Execution_bundle)); 118 | 119 | struct Scopes * scopes = malloc_or_die(sizeof(struct Scopes)); 120 | scopes->scopes = NULL; 121 | RESIZE(scopes->scopes, 1); 122 | scopes->size = 1; 123 | scopes->current = 0; 124 | 125 | scopes->scopes[0] = hash_table_new(&string_hash_code_vv, &string_matches_vv); 126 | 127 | exec_bundle->scopes = scopes; 128 | for(size_t i = 0; i < ast_size(root); i++){ 129 | exec_bundle->max_depth = RECURSE_MAX; 130 | exec_bundle->ast = ast_child(root, i); 131 | execute(exec_bundle); 132 | } 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /src/huo.h: -------------------------------------------------------------------------------- 1 | #ifndef _HUO_H 2 | #define _HUO_H 3 | 4 | char *get_exe_path(const char *called_name); 5 | char *get_path_dir(char *path); 6 | char *path_merge(const char *dir, const char *rest); 7 | int main(int argc, char const *argv[]); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/parser.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "structures/structures.h" 6 | #include "constants.h" 7 | #include "core_functions.h" 8 | #include "config.h" 9 | 10 | typedef huo_ast *parse_func(size_t *pos, struct Tokens *tokens); 11 | 12 | void free_if_nonnull(void *v); 13 | 14 | struct Token get_token(size_t *pos, struct Tokens *tokens); 15 | bool accept(huo_ast **, size_t *pos, struct Tokens *tokens, parse_func *to_accept); 16 | bool discard(size_t *pos, struct Tokens *tokens, parse_func *to_accept); 17 | bool discard_any(size_t *pos, struct Tokens *tokens, size_t num_to_accept, parse_func **to_accept); 18 | bool accept_any(huo_ast **ret, size_t *pos, struct Tokens *tokens, size_t num_to_accept, parse_func **to_accept); 19 | huo_ast *parse_whitespace(size_t *pos, struct Tokens *tokens); 20 | huo_ast *parse_newline(size_t *pos, struct Tokens *tokens); 21 | huo_ast *parse_comment(size_t *pos, struct Tokens *tokens); 22 | bool discard_whitespace(size_t *pos, struct Tokens *tokens); 23 | huo_ast *parse_eof(size_t *pos, struct Tokens *tokens); 24 | huo_ast *parse_main(size_t *pos, struct Tokens *tokens); 25 | huo_ast *parse_function(size_t *pos, struct Tokens *tokens); 26 | huo_ast *parse_open_bracket_internals(size_t *pos, struct Tokens *tokens); 27 | huo_ast *parse_open_bracket(size_t *pos, struct Tokens *tokens); 28 | huo_ast *parse_statement(size_t *pos, struct Tokens *tokens); 29 | huo_ast *parse_float(size_t *pos, struct Tokens *tokens); 30 | huo_ast *parse_int(size_t *pos, struct Tokens *tokens); 31 | huo_ast *parse_number(size_t *pos, struct Tokens *tokens); 32 | huo_ast *parse_word(size_t *pos, struct Tokens *tokens); 33 | huo_ast *parse_quote(size_t *pos, struct Tokens *tokens); 34 | huo_ast *parse_open_square(size_t *pos, struct Tokens *tokens); 35 | 36 | #define EXPECT(pos, tokens, to, x) do {if (!accept((to), (pos), (tokens), (x))) {return NULL;}} while (0) 37 | #define EXPECT_TOKEN(pos, tokens, x) do {if (get_token((pos), (tokens)).type != (x)) {return NULL;} (*(pos)) += 1;} while (0) 38 | 39 | char *token_print(struct Token t) { 40 | struct String st = string_from_chars(enum_name_token_type_t(t.type)); 41 | struct String *s = string_copy_heap(&st); 42 | struct String c = string_from_chars(": "); 43 | string_concat_to(s, &c); 44 | string_concat_to(s, &t.data); 45 | return string_to_chars(s); 46 | } 47 | 48 | void free_if_nonnull(void *v) { 49 | if (v != NULL) 50 | free(v); 51 | } 52 | 53 | struct Token get_token(size_t *pos, struct Tokens *tokens) { 54 | //printf("%zu: %s\n", *pos, token_print(tokens->tokens[*pos])); 55 | return tokens->tokens[*pos]; 56 | } 57 | 58 | bool accept(huo_ast **ret, size_t *pos, struct Tokens *tokens, parse_func *to_accept) { 59 | size_t c_pos = *pos; 60 | huo_ast *temp = to_accept(pos, tokens); 61 | if (temp == NULL) { 62 | *pos = c_pos; 63 | //ret = ret; // Needed or else ret is considered uninit, and as such 64 | return false; 65 | } else { 66 | *ret = temp; 67 | //*pos = *pos; 68 | return true; 69 | } 70 | } 71 | 72 | bool peek_token(size_t *pos, struct Tokens *tokens, enum token_type_t token) { 73 | return (get_token(pos, tokens).type == token); 74 | } 75 | 76 | struct Token next_token(size_t *pos, struct Tokens *tokens) { 77 | return tokens->tokens[(*pos)++]; 78 | } 79 | 80 | bool discard_token(size_t *pos, struct Tokens *tokens, enum token_type_t token) { 81 | if (get_token(pos, tokens).type == token) { 82 | (*pos)++; 83 | return true; 84 | } else { 85 | return false; 86 | } 87 | } 88 | 89 | bool discard(size_t *pos, struct Tokens *tokens, parse_func *to_accept) { 90 | huo_ast *ret = NULL; 91 | bool b = accept(&ret, pos, tokens, to_accept); 92 | if (b) { 93 | free_if_nonnull(ret); 94 | } 95 | return b; 96 | } 97 | 98 | bool discard_any(size_t *pos, struct Tokens *tokens, size_t num_to_accept, parse_func **to_accept) { 99 | for (size_t i = 0; i < num_to_accept; i++) { 100 | if (discard(pos, tokens, to_accept[i])) { 101 | return true; 102 | } 103 | } 104 | return false; 105 | } 106 | 107 | bool accept_any(huo_ast **ret, size_t *pos, struct Tokens *tokens, size_t num_to_accept, parse_func **to_accept) { 108 | for (size_t i = 0; i < num_to_accept; i++) { 109 | if (accept(ret, pos, tokens, to_accept[i])) { 110 | return true; 111 | } 112 | } 113 | return false; 114 | } 115 | 116 | bool discard_whitespace(size_t *pos, struct Tokens *tokens) { 117 | bool discarded = false; 118 | while ( discard_token(pos, tokens, TOK_WHITESPACE) 119 | || discard_token(pos, tokens, TOK_NEWLINE) 120 | || discard_token(pos, tokens, TOK_COMMENT)) { 121 | discarded = true; 122 | } 123 | return discarded; 124 | } 125 | 126 | huo_ast *parse(struct Tokens *tokens) { 127 | //for (size_t i = 0; i < tokens->length; i++) { 128 | // printf("%zu: %s\n", i, token_print(get_token(&i, tokens))); 129 | //} 130 | size_t pos = 0; 131 | huo_ast *ast = NULL; 132 | discard_whitespace(&pos, tokens); 133 | if (accept(&ast, &pos, tokens, parse_main)) { 134 | 135 | } else if (accept(&ast, &pos, tokens, parse_open_bracket)) { 136 | 137 | } else if (accept(&ast, &pos, tokens, parse_open_square)) { 138 | 139 | } else { 140 | ERROR("Invalid parse!"); 141 | } 142 | discard_whitespace(&pos, tokens); 143 | EXPECT_TOKEN(&pos, tokens, TOK_EOF); 144 | return ast; 145 | } 146 | 147 | huo_ast *parse_main(size_t *pos, struct Tokens *tokens) { 148 | huo_ast *tree = ast_new(AST_STATEMENT, value_from_undef()); 149 | 150 | while (true) { 151 | discard_whitespace(pos, tokens); 152 | huo_ast *child = NULL; 153 | if (peek_token(pos, tokens, TOK_EOF)) { 154 | break; 155 | } else if (peek_token(pos, tokens, TOK_CLOSE_BRACKET)) { 156 | break; 157 | } else if (accept(&child, pos, tokens, parse_statement)) { 158 | ast_push_child(tree, child); 159 | } else { 160 | ERROR("Unknown token: %s", token_print(get_token(pos, tokens))); 161 | } 162 | } 163 | return tree; 164 | } 165 | 166 | huo_ast *parse_open_bracket(size_t *pos, struct Tokens *tokens) { 167 | discard_whitespace(pos, tokens); 168 | 169 | EXPECT_TOKEN(pos, tokens, TOK_OPEN_BRACKET); 170 | 171 | huo_ast *tree = NULL; 172 | 173 | EXPECT(pos, tokens, &tree, parse_main); 174 | 175 | discard_whitespace(pos, tokens); 176 | 177 | EXPECT_TOKEN(pos, tokens, TOK_CLOSE_BRACKET); 178 | 179 | return tree; 180 | 181 | } 182 | 183 | huo_ast *parse_statement(size_t *pos, struct Tokens *tokens) { 184 | discard_whitespace(pos, tokens); 185 | 186 | parse_func *norm_children[] = { 187 | parse_number, 188 | parse_word, 189 | parse_open_bracket, 190 | parse_open_square, 191 | parse_quote 192 | }; 193 | 194 | huo_ast *child = NULL; 195 | accept_any(&child, pos, tokens, 5, norm_children); 196 | return child; 197 | } 198 | 199 | 200 | huo_ast *parse_float(size_t *pos, struct Tokens *tokens) { 201 | struct Token int_tok = get_token(pos, tokens); 202 | 203 | struct String int_str; 204 | if (discard_token(pos, tokens, TOK_NUMBER)) { 205 | int_str = int_tok.data; 206 | } else { 207 | int_str = string_from_char('0'); 208 | } 209 | EXPECT_TOKEN(pos, tokens, TOK_DOT); 210 | struct Token frac_tok = get_token(pos, tokens); 211 | EXPECT_TOKEN(pos, tokens, TOK_NUMBER); 212 | struct String frac_str = frac_tok.data; 213 | 214 | struct String dot_str = string_from_char('.'); 215 | string_concat_to(&int_str, &dot_str); 216 | string_concat_to(&int_str, &frac_str); 217 | 218 | char *str = string_to_chars(&int_str); 219 | 220 | float f_val; 221 | 222 | sscanf(str, "%f", &f_val); 223 | free_if_nonnull(str); 224 | 225 | return ast_new(AST_FLOAT, value_from_float(f_val)); 226 | } 227 | 228 | huo_ast *parse_int(size_t *pos, struct Tokens *tokens) { 229 | struct Token t = get_token(pos, tokens); 230 | 231 | EXPECT_TOKEN(pos, tokens, TOK_NUMBER); 232 | 233 | huo_int_t int_val; 234 | 235 | sscanf(string_to_chars(&t.data), "%" SCNhi, &int_val); 236 | 237 | huo_ast *tree = ast_new(AST_INTEGER, value_from_long(int_val)); 238 | 239 | assert (get_token(pos, tokens).type != TOK_DOT); 240 | 241 | return tree; 242 | } 243 | 244 | huo_ast *parse_number(size_t *pos, struct Tokens *tokens) { 245 | discard_whitespace(pos, tokens); 246 | bool sign = false; 247 | bool found_sign = false; 248 | while (true) { 249 | if (discard_token(pos, tokens, TOK_MINUS)) { 250 | sign = !sign; 251 | } else if (discard_token(pos, tokens, TOK_PLUS)) { 252 | // pass 253 | } else { 254 | break; 255 | } 256 | if (found_sign) { 257 | WARN_ONCE("Multiple signs found!"); 258 | } else { 259 | found_sign = true; 260 | } 261 | } 262 | 263 | huo_ast *tree = NULL; 264 | 265 | // Must parse float before int. 266 | bool parsed = accept(&tree, pos, tokens, parse_float); 267 | 268 | if (!parsed) { 269 | parsed = accept(&tree, pos, tokens, parse_int); 270 | } 271 | 272 | if (parsed && sign) { 273 | value_negate(ast_value(tree)); 274 | } 275 | return tree; 276 | } 277 | 278 | huo_ast *parse_word(size_t *pos, struct Tokens *tokens) { 279 | discard_whitespace(pos, tokens); 280 | 281 | struct Token t = get_token(pos, tokens); 282 | //printf("Parsing word at %zu %s", *pos, token_print(t)); 283 | 284 | switch (t.type) { 285 | case TOK_PLUS: 286 | case TOK_MINUS: 287 | case TOK_BUILTIN: 288 | case TOK_WORD: 289 | break; 290 | case TOK_DOT: 291 | case TOK_COMMA: 292 | case TOK_OPEN_BRACKET: 293 | case TOK_CLOSE_BRACKET: 294 | case TOK_OPEN_SQUARE: 295 | case TOK_CLOSE_SQUARE: 296 | case TOK_NUMBER: 297 | case TOK_QUOTE: 298 | return NULL; 299 | default: 300 | assert(false); 301 | } 302 | 303 | next_token(pos, tokens); 304 | 305 | return ast_new(AST_KEYWORD, value_from_keyword(&t.data)); 306 | } 307 | 308 | huo_ast *parse_quote(size_t *pos, struct Tokens *tokens) { 309 | discard_whitespace(pos, tokens); 310 | struct Token t = get_token(pos, tokens); 311 | 312 | EXPECT_TOKEN(pos, tokens, TOK_QUOTE); 313 | 314 | struct String str = string_copy_stack(&t.data); 315 | 316 | size_t len = string_length(&str); 317 | 318 | struct Value val = value_from_string(str); 319 | 320 | // Remove quotes 321 | return ast_new(AST_STRING, substring_ll(1,len - 1, val)); 322 | } 323 | 324 | huo_ast *parse_array(size_t *pos, struct Tokens *tokens) { 325 | 326 | discard_whitespace(pos, tokens); 327 | 328 | huo_ast *tree = ast_new(AST_ARRAY, value_from_undef()); 329 | 330 | while (true) { 331 | 332 | discard_whitespace(pos, tokens); 333 | 334 | huo_ast *child = NULL; 335 | 336 | if (peek_token(pos, tokens, TOK_EOF)) { 337 | break; 338 | } else if (peek_token(pos, tokens, TOK_CLOSE_SQUARE)) { 339 | break; 340 | } else if (accept(&child, pos, tokens, parse_statement)) { 341 | ast_push_child(tree, child); 342 | //} else if (discard_token(pos, tokens, TOK_COMMA)) { 343 | // ast_push_child(tree, ast_new(AST_UNDEF, value_from_undef())); 344 | } else { 345 | break; 346 | } 347 | 348 | discard_whitespace(pos, tokens); 349 | 350 | if (peek_token(pos, tokens, TOK_CLOSE_SQUARE)) { 351 | break; 352 | } 353 | 354 | EXPECT_TOKEN(pos, tokens, TOK_COMMA); 355 | } 356 | return tree; 357 | } 358 | 359 | huo_ast *parse_open_square(size_t *pos, struct Tokens *tokens) { 360 | discard_whitespace(pos, tokens); 361 | EXPECT_TOKEN(pos, tokens, TOK_OPEN_SQUARE); 362 | 363 | huo_ast *tree = NULL; 364 | 365 | EXPECT(pos, tokens, &tree, parse_array); 366 | discard_whitespace(pos, tokens); 367 | discard_token(pos, tokens, TOK_COMMA); // Allow trailing comma. 368 | discard_whitespace(pos, tokens); 369 | 370 | EXPECT_TOKEN(pos, tokens, TOK_CLOSE_SQUARE); 371 | return tree; 372 | } 373 | 374 | -------------------------------------------------------------------------------- /src/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef _PARSER_H 2 | #define _PARSER_H 3 | 4 | #include "structures/structures.h" 5 | 6 | huo_ast *parse(struct Tokens *tokens); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/path_utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if defined(_POSIX_VERSION) || defined(__linux__) || defined(__APPLE__) 6 | #include 7 | #include "base_util.h" 8 | 9 | char *get_exe_path(const char *called_name) { 10 | char *path_to_exe = realpath(called_name, NULL); 11 | 12 | if (path_to_exe == NULL) { 13 | ERROR("Error getting real path: %d (%s)", errno, strerror(errno)); 14 | } 15 | 16 | return path_to_exe; 17 | } 18 | 19 | char *get_path_dir(char *path) { 20 | char *temp = dirname(path); 21 | if (temp == NULL) { 22 | ERROR("Error splitting directory: %s", path); 23 | } 24 | char *dup = o_strdup(temp); // dirname strings should not be freed 25 | if (dup == NULL) { 26 | ERROR("Malloc failure"); 27 | } 28 | return dup; 29 | } 30 | 31 | char *path_merge(const char *dir, const char *rest) { 32 | // Bleh 33 | char *path = ARR_MALLOC(strlen(dir) + 1 + strlen(rest) + 1, char); // sizeof(char) is defined as 1, I know. 34 | if (path == NULL) { 35 | ERROR("Malloc failure"); 36 | } 37 | path[0] = 0; 38 | strcat(path, dir); 39 | strcat(path, "/"); 40 | strcat(path, rest); 41 | return path; 42 | } 43 | #elif defined(_WIN16) || defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) 44 | // UNTESTED!! 45 | #include 46 | #include "base_util.h" 47 | 48 | 49 | char *get_exe_path(const char *called_name) { 50 | char *buffer = malloc_or_die(MAX_PATH); 51 | GetModuleFileName(NULL, buffer, MAX_PATH) ; 52 | 53 | return buffer; 54 | } 55 | 56 | char *get_path_dir(char *path) { 57 | // Bleh 58 | char *temp = o_strdup(path); 59 | size_t len = strlen(temp); 60 | do { 61 | temp[len] = 0; 62 | if (len <= 1) { 63 | ERROR("Could not find directory of %s", path); 64 | } 65 | } while (temp[--len] != '/' && temp[--len] != '\\'); 66 | temp[len] = 0; 67 | return temp; 68 | } 69 | 70 | char *path_merge(const char *dir, const char *rest) { 71 | char *path = ARR_MALLOC(strlen(dir) + 1 + strlen(rest) + 1, char); 72 | if (path == NULL) { 73 | ERROR("Malloc failure"); 74 | } 75 | path[0] = 0; 76 | strcat(path, dir); 77 | strcat(path, "\\"); 78 | strcat(path, rest); 79 | return path; 80 | } 81 | #else 82 | #error "Unknown system!" 83 | #endif 84 | -------------------------------------------------------------------------------- /src/path_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _PATH_UTILS_H 2 | #define _PATH_UTILS_H 3 | 4 | char *get_exe_path(const char *called_name); 5 | char *get_path_dir(char *path); 6 | char *path_merge(const char *dir, const char *rest); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/process_defs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "core_functions.h" 5 | #include "process_defs.h" 6 | #include "execute.h" 7 | #include "execution_functions/let_binding.h" 8 | #include "structures/hash_table.h" 9 | #include "base_util.h" 10 | #include "config.h" 11 | 12 | void make_args_map(struct Execution_bundle * exec_bundle, huo_ast * function) { 13 | huo_ast * ast = exec_bundle->ast; 14 | // we want to evaluate the values passed into the function 15 | // but store the result in the next scope, not the current one 16 | if (ast_size(function) != ast_size(ast) + 2) { 17 | ERROR("Wrong number of arguments!: %zu != %zu", ast_size(function) < 2 ? 0 : ast_size(function) - 2, ast_size(ast)); 18 | } 19 | struct Value vals[ast_size(ast)]; 20 | for(size_t i = 0; i + 1 < ast_size(ast); i++){ 21 | exec_bundle->ast = ast_child(ast, i+1); 22 | vals[i] = execute(exec_bundle); 23 | } 24 | exec_bundle->ast = ast; 25 | push_scope(exec_bundle->scopes); 26 | for(size_t i = 0; i + 1 < ast_size(ast); i++){ 27 | char t = ast_value(ast_child(function, i + 2))->type; 28 | if (t != TYPE_KEYWORD) { 29 | ERROR("Invalid type for argument: '%c' != TYPE_KEYWORD", t); 30 | } 31 | store_let_value(ast_value(ast_child(function, i + 2)), &vals[i], exec_bundle->scopes); 32 | } 33 | } 34 | 35 | huo_ast * get_defined_body(huo_ast * function){ 36 | // just pulls the function body out of a (def...) 37 | if (ast_size(function) <= 1) { 38 | ERROR("No function body!"); 39 | } 40 | size_t index = ast_size(function) - 1; 41 | huo_ast *child = ast_child(function, index); 42 | if (ast_size(child) == 0) { 43 | ERROR("No function body!"); 44 | } 45 | return ast_copy(child); 46 | } 47 | 48 | struct definition *get_defined(struct Scopes *scopes, struct String key) { 49 | //printf("DEFINED:\n"); 50 | // for (size_t i = 0; i <= scopes->current; i++) { 51 | // for (hash_table_iter *t = hash_table_iter_new(scopes->scopes[i]); hash_table_iter_has_cur(t); hash_table_iter_next(t)) { 52 | // struct String *k = hash_table_iter_key(t); 53 | // struct definition *v = hash_table_iter_val(t); 54 | // if (v->is_func) { 55 | // printf("%s -> func\n", string_to_chars(k)); 56 | // } else { 57 | // printf("%s -> '", string_to_chars(k)); 58 | // print(*(v->val.val)); 59 | // printf("'\n"); 60 | // } 61 | // } 62 | // } 63 | //printf("'%s'\n", string_to_chars(&key)); 64 | assert(string_is_sane(&key)); 65 | for (size_t ipo = scopes->current + 1; ipo > 0; ipo--) { 66 | size_t i = ipo - 1; 67 | hash_table *current_scope = scopes->scopes[i]; 68 | struct definition *def = (struct definition *) hash_table_get(current_scope, &key); 69 | if (def != NULL) { 70 | return def; 71 | } 72 | } 73 | return NULL; 74 | } 75 | 76 | huo_ast *get_defined_func(struct Scopes *defined, struct String key) { 77 | // printf("DEF '%s'\n", string_to_chars(&key)); 78 | struct definition *def = get_defined(defined, key); 79 | if(def == NULL || !def->is_func) { 80 | // printf("FALSE\n"); 81 | return NULL; 82 | } else { 83 | // printf("TRUE\n"); 84 | return def->val.ast; 85 | } 86 | } 87 | 88 | struct Value *get_letted_value(struct Scopes *defined, struct String key) { 89 | // printf("LET '%s'\n", string_to_chars(&key)); 90 | struct definition *def = get_defined(defined, key); 91 | if(def == NULL || def->is_func) { 92 | // printf("FALSE\n"); 93 | return NULL; 94 | } else { 95 | // printf("TRUE\n"); 96 | return def->val.val; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/process_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROCESS_DEFS_H 2 | #define _PROCESS_DEFS_H 3 | 4 | #include "structures/structures.h" 5 | 6 | void make_args_map(struct Execution_bundle * exec_bundle, huo_ast * function); 7 | huo_ast *get_defined_body(huo_ast * function); 8 | huo_ast *get_defined_func(struct Scopes *defined, struct String key); 9 | struct Value *get_letted_value(struct Scopes *defined, struct String key); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/store_defs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "structures/structures.h" 5 | #include "constants.h" 6 | #include "store_defs.h" 7 | #include "tokenizer.h" 8 | #include "parser.h" 9 | #include "execution_functions/read_file.h" 10 | #include "structures/hash_table.h" 11 | #include "config.h" 12 | 13 | huo_ast * read_import(struct String file_name){ 14 | assert(string_is_sane(&file_name)); 15 | struct String file_contents = read_file(file_name); 16 | struct Tokens * tokens = malloc_or_die(sizeof(struct Tokens)); 17 | tokens->tokens = NULL; 18 | tokens->length = 0; 19 | tokens->counter = 0; 20 | 21 | tokenize(file_contents, tokens); 22 | huo_ast *root = parse(tokens); 23 | 24 | free(tokens); 25 | return root; 26 | } 27 | -------------------------------------------------------------------------------- /src/store_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef _STORE_DEFS_H 2 | #define _STORE_DEFS_H 3 | 4 | #include "structures/structures.h" 5 | 6 | huo_ast * read_import(struct String file_name); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/structures/array.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "../config.h" 3 | #include "../base_util.h" 4 | 5 | void array_copy_to(struct Value_array *to, struct Value_array *from) { 6 | if (from->size == 0) { 7 | RESIZE(to->values, 0); 8 | to->size = 0; 9 | } else { 10 | if (to->size != from->size) { 11 | RESIZE(to->values, from->size); 12 | to->size = from->size; 13 | } 14 | for(size_t i = 0; i < from->size; i++){ 15 | to->values[i] = value_copy_heap(from->values[i]); 16 | } 17 | } 18 | } 19 | 20 | struct Value_array array_copy_stack(struct Value_array * from){ 21 | struct Value_array array; 22 | array.size = from->size; 23 | array.values = ARR_MALLOC(array.size, array.values[0]); 24 | for(size_t i = 0; i < from->size; i++){ 25 | array.values[i] = value_copy_heap(from->values[i]); 26 | } 27 | return array; 28 | } 29 | 30 | struct Value_array *array_copy_heap(struct Value_array * from){ 31 | struct Value_array * array = malloc_or_die(sizeof(struct Value_array)); 32 | array->size = from->size; 33 | array->values = ARR_MALLOC(array->size, array->values[0]); 34 | for(size_t i = 0; i < from->size; i++){ 35 | array->values[i] = value_copy_heap(from->values[i]); 36 | } 37 | return array; 38 | } 39 | 40 | struct Value_array *array_concat_heap(struct Value_array *a, struct Value_array *b) { 41 | struct Value_array *temp = array_copy_heap(a); 42 | array_concat_to(temp, b); 43 | return temp; 44 | } 45 | 46 | void array_concat_to(struct Value_array *to, struct Value_array *from) { 47 | size_t len = to->size; 48 | to->size += from->size; 49 | RESIZE(to->values, to->size); 50 | for(size_t l = 0; l < from->size; l++){ 51 | to->values[l+len] = value_copy_heap(from->values[l]); 52 | } 53 | } 54 | 55 | bool array_matches(struct Value_array *base, struct Value_array *compare){ 56 | if(base->size != compare->size){ 57 | return false; 58 | } 59 | for (size_t i = 0; i < base->size; i++) { 60 | if (!value_equals_shallow(base->values[i], compare->values[i])) 61 | return false; 62 | } 63 | return true; 64 | } 65 | 66 | bool array_contains(struct Value *item, struct Value_array *array){ 67 | enum Value_type t = item->type; 68 | for(size_t i = 0; i < array->size; i++){ 69 | if(array->values[i]->type == t){ 70 | if(array->values[i]->type == TYPE_KEYWORD && t == TYPE_KEYWORD){ 71 | if(string_matches_heap(&array->values[i]->data.str, &item->data.str)){ 72 | return true; 73 | } 74 | } 75 | else if (t == TYPE_FLOAT){ 76 | if(array->values[i]->data.fl == item->data.fl){ 77 | return true; 78 | } 79 | } 80 | } 81 | } 82 | return false; 83 | } 84 | 85 | void array_free_content(struct Value_array *array) { 86 | for(size_t i = 0; i < array->size; i++){ 87 | value_free(array->values[i]); 88 | } 89 | if (array->values != NULL) { 90 | free(array->values); 91 | } 92 | } 93 | 94 | void array_free(struct Value_array *array) { 95 | if (array != NULL) { 96 | array_free_content(array); 97 | free(array); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/structures/array.h: -------------------------------------------------------------------------------- 1 | #ifndef HUO_ARRAY_H 2 | #define HUO_ARRAY_H 1 3 | 4 | #include 5 | #include 6 | 7 | struct Value_array { 8 | size_t size; 9 | struct Value **values; 10 | }; 11 | 12 | void array_copy_to(struct Value_array *to, struct Value_array *from); 13 | struct Value_array array_copy_stack(struct Value_array *arr); 14 | struct Value_array *array_copy_heap(struct Value_array *arr); 15 | struct Value_array *array_concat_heap(struct Value_array *a, struct Value_array *b); 16 | void array_concat_to(struct Value_array *to, struct Value_array *from); 17 | bool array_matches(struct Value_array *base, struct Value_array *compare); 18 | bool array_contains(struct Value *item, struct Value_array *array); 19 | 20 | void array_free(struct Value_array *array); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/structures/hash_table.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "hash_table.h" 5 | #include "../base_util.h" 6 | #include "../config.h" 7 | 8 | void *hash_table_put_int(hash_table *table, void *key, void *val, unsigned long hash_code); 9 | size_t get_distance(hash_table *table, size_t cur_pos); 10 | void print_table(hash_table *table); 11 | bool hash_table_needs_resize(hash_table *table); 12 | void hash_table_resize(hash_table *table, size_t new_size); 13 | bool hash_table_is_sane(hash_table *table); 14 | 15 | 16 | /* 17 | * A simple hash table, using robin hood hashing. 18 | * 19 | * Basic idea behind "robin hood" hashing: it's like linear probing, 20 | * but you can "kick out" another slot if you're further from your preferred slot 21 | * than they are. 22 | * 23 | * To use, just implement hash_code_func and equals_func. 24 | * It must always be the case that equals_func(a,b) implies hash_code_func(a) == hash_code_func(b), 25 | * but not necessarily the other way around. 26 | * 27 | * 28 | * */ 29 | 30 | #define HASH_TABLE_MIN_SIZE 16 31 | 32 | #define HASH_TABLE_MAX_LOAD_NUM 3 33 | #define HASH_TABLE_MAX_LOAD_DENOM 4 34 | 35 | #define HASH_TABLE_MIN_LOAD_NUM 1 36 | #define HASH_TABLE_MIN_LOAD_DENOM 4 37 | 38 | #define HASH_TABLE_EXPAND_NUM 3 39 | #define HASH_TABLE_EXPAND_DENOM 2 40 | 41 | #define HASH_TABLE_SHRINK_NUM 2 42 | #define HASH_TABLE_SHRINK_DENOM 3 43 | 44 | STATIC_ASSERT(HASH_TABLE_MAX_LOAD_NUM * HASH_TABLE_EXPAND_NUM * HASH_TABLE_MIN_LOAD_DENOM > HASH_TABLE_MIN_LOAD_NUM * HASH_TABLE_MAX_LOAD_DENOM * HASH_TABLE_EXPAND_DENOM, "Hash_table_expands_too_much"); 45 | 46 | STATIC_ASSERT(HASH_TABLE_MIN_LOAD_NUM * HASH_TABLE_SHRINK_NUM * HASH_TABLE_MAX_LOAD_DENOM < HASH_TABLE_MAX_LOAD_NUM * HASH_TABLE_MIN_LOAD_DENOM * HASH_TABLE_SHRINK_DENOM, "Hash_table_shrinks_too_much"); 47 | 48 | STATIC_ASSERT(HASH_TABLE_EXPAND_NUM > HASH_TABLE_EXPAND_DENOM, "Expand_ratio_less_than_or_equal_1"); 49 | 50 | STATIC_ASSERT(HASH_TABLE_SHRINK_NUM < HASH_TABLE_SHRINK_DENOM, "Shrink_ratio_greater_than_or_equal_1"); 51 | 52 | STATIC_ASSERT(HASH_TABLE_MAX_LOAD_NUM < HASH_TABLE_MAX_LOAD_DENOM, "Max_load_greater_than_or_equal_1"); 53 | 54 | STATIC_ASSERT(HASH_TABLE_MAX_LOAD_NUM * HASH_TABLE_MAX_LOAD_DENOM > 0, "Max_load_less_than_or_equal_0"); 55 | 56 | STATIC_ASSERT(HASH_TABLE_MIN_LOAD_NUM < HASH_TABLE_MIN_LOAD_DENOM, "Min_load_greater_than_or_equal_1"); 57 | 58 | STATIC_ASSERT(HASH_TABLE_MIN_LOAD_NUM * HASH_TABLE_MIN_LOAD_DENOM > 0, "Min_load_less_than_or_equal_0"); 59 | 60 | STATIC_ASSERT(HASH_TABLE_MAX_LOAD_NUM * HASH_TABLE_MIN_LOAD_DENOM > HASH_TABLE_MAX_LOAD_DENOM * HASH_TABLE_MIN_LOAD_NUM,"Max_load_less_than_or_equal_min_load"); 61 | 62 | const char DUMMY = 'd'; 63 | #define NO_ELEMENT ((char *) &DUMMY) 64 | 65 | 66 | struct hash_table_entry_t { 67 | unsigned long hash_code; 68 | void *key; 69 | void *val; 70 | }; 71 | 72 | struct hash_table_t { 73 | struct hash_table_entry_t *table; 74 | size_t table_size; 75 | size_t table_alloc_size; 76 | hash_code_func *hash_gen; 77 | equals_func *equality_test; 78 | }; 79 | 80 | struct hash_table_iter_t { 81 | hash_table *table; 82 | size_t pos; 83 | }; 84 | 85 | hash_table *hash_table_new(hash_code_func *hash_gen, equals_func *equality_test) { 86 | hash_table *h = malloc_or_die(sizeof(hash_table)); 87 | if (h == NULL) { 88 | ERROR("Malloc failure"); 89 | } 90 | h->table = NULL; 91 | h->table_size = 0; 92 | h->table_alloc_size = 0; 93 | h->hash_gen = hash_gen; 94 | h->equality_test = equality_test; 95 | hash_table_resize(h, HASH_TABLE_MIN_SIZE); 96 | assert(hash_table_is_sane(h)); 97 | return h; 98 | } 99 | 100 | bool hash_table_slot_is_free(struct hash_table_entry_t *entry) { 101 | return entry->key == NO_ELEMENT; 102 | } 103 | 104 | bool hash_table_is_sane(hash_table *table) { 105 | //print_table(table); 106 | assert (table != NULL); 107 | assert (table->table_size <= table->table_alloc_size); 108 | assert (table->table_alloc_size >= HASH_TABLE_MIN_SIZE); 109 | if (table->table_alloc_size > 0) 110 | assert(table->table != NULL); 111 | size_t num_ele = 0; 112 | for (size_t l = 0; l < table->table_alloc_size; l++) { 113 | struct hash_table_entry_t *e = &table->table[l]; 114 | if (hash_table_slot_is_free(e)) 115 | continue; 116 | assert(get_distance(table, l) <= table->table_alloc_size); 117 | assert(e->hash_code == table->hash_gen(e->key)); 118 | num_ele += 1; 119 | size_t pos = l; 120 | size_t pref_pos = (e->hash_code) % table->table_alloc_size; 121 | while (true) { 122 | if (pos == pref_pos) 123 | break; 124 | assert (!hash_table_slot_is_free(&table->table[pos])); 125 | pos = (pos - 1 + table->table_alloc_size) % table->table_alloc_size; // Negative wraparound, otherwise 126 | } 127 | } 128 | assert (num_ele == table->table_size); 129 | assert (!hash_table_needs_resize(table)); 130 | return true; 131 | } 132 | 133 | bool hash_table_too_empty(hash_table *table) { 134 | size_t s = table->table_size; 135 | size_t a = table->table_alloc_size; 136 | return s > HASH_TABLE_MIN_SIZE && s * HASH_TABLE_MIN_LOAD_DENOM < a * HASH_TABLE_MIN_LOAD_NUM; 137 | } 138 | 139 | bool hash_table_too_full(hash_table *table) { 140 | size_t s = table->table_size; 141 | size_t a = table->table_alloc_size; 142 | return s * HASH_TABLE_MAX_LOAD_DENOM > a * HASH_TABLE_MAX_LOAD_NUM; 143 | } 144 | 145 | bool hash_table_needs_resize(hash_table *table) { 146 | return hash_table_too_empty(table) || hash_table_too_full(table); 147 | } 148 | 149 | void hash_table_resize(hash_table *table, size_t new_size) { 150 | //assert(hash_table_is_sane(table)); 151 | // Called by constructor, and as such may have too few elements 152 | assert (new_size >= table->table_size); 153 | assert (new_size >= HASH_TABLE_MIN_SIZE); 154 | size_t old_alloc_size = table->table_alloc_size; 155 | struct hash_table_entry_t *old_table = table->table; 156 | 157 | size_t num_ele = table->table_size; 158 | table->table_size = 0; 159 | table->table_alloc_size = new_size; 160 | table->table = ARR_MALLOC(new_size, struct hash_table_entry_t); 161 | 162 | // Set elements to uninitialized 163 | for (size_t i = 0; i < new_size; i++) { 164 | struct hash_table_entry_t entry = { 165 | .hash_code = 0, 166 | .key = NO_ELEMENT, 167 | .val = NULL 168 | }; 169 | table->table[i] = entry; 170 | } 171 | 172 | // Reinsert old elements where necessary. 173 | for (size_t i = 0; i < old_alloc_size; i++) { 174 | struct hash_table_entry_t *entry = &old_table[i]; 175 | if (!hash_table_slot_is_free(entry)) { 176 | hash_table_put_int(table, entry->key, entry->val, entry->hash_code); 177 | } 178 | } 179 | free(old_table); 180 | assert(hash_table_is_sane(table)); 181 | assert(table->table_size == num_ele); 182 | } 183 | 184 | void hash_table_maybe_resize(hash_table *table) { 185 | size_t size = table->table_alloc_size; 186 | size_t new_size; 187 | if (hash_table_too_full(table)) { 188 | new_size = size * HASH_TABLE_EXPAND_NUM / HASH_TABLE_EXPAND_DENOM; 189 | if (new_size <= size) 190 | new_size = size + 1; 191 | } else if (hash_table_too_empty(table)) { 192 | new_size = size * HASH_TABLE_SHRINK_NUM / HASH_TABLE_SHRINK_DENOM; 193 | if (new_size >= size) 194 | new_size = size - 1; 195 | } else { 196 | return; 197 | } 198 | if (new_size < HASH_TABLE_MIN_SIZE) 199 | new_size = HASH_TABLE_MIN_SIZE; 200 | hash_table_resize(table, new_size); 201 | assert (!hash_table_needs_resize(table)); 202 | } 203 | 204 | size_t get_distance(hash_table *table, size_t cur_pos) { 205 | //assert (cur_pos >= 0); 206 | assert (cur_pos < table->table_alloc_size); 207 | struct hash_table_entry_t *entry = &table->table[cur_pos]; 208 | assert (!hash_table_slot_is_free(entry)); 209 | size_t init_pos = table->table[cur_pos].hash_code % table->table_alloc_size; 210 | if (init_pos <= cur_pos) 211 | return cur_pos - init_pos; 212 | else 213 | return cur_pos + (table->table_alloc_size - init_pos); 214 | } 215 | 216 | void *hash_table_put_int(hash_table *table, void *key, void *val, unsigned long hash_code) { 217 | unsigned long init_hash_code = hash_code; 218 | assert(hash_table_is_sane(table)); 219 | while (true) { 220 | size_t probe_current = 0; 221 | for (size_t i = 0; i < table->table_alloc_size; i++) { 222 | size_t table_pos = (init_hash_code + i) % table->table_alloc_size; 223 | struct hash_table_entry_t *entry = &table->table[table_pos]; 224 | bool was_free = hash_table_slot_is_free(entry); 225 | if (was_free || (entry->hash_code == hash_code && table->equality_test(entry->key, key))) { 226 | // Right entry, now kick it out. 227 | void *old_val = entry->val; 228 | entry->hash_code = hash_code; 229 | entry->key = key; 230 | entry->val = val; 231 | if (was_free) { 232 | table->table_size += 1; 233 | hash_table_maybe_resize(table); 234 | } 235 | assert(hash_table_is_sane(table)); 236 | return old_val; 237 | } 238 | 239 | size_t probe_distance = get_distance(table, table_pos); 240 | 241 | if (probe_current > probe_distance){ 242 | // swap current entry with entry to insert 243 | struct hash_table_entry_t temp = *entry; 244 | entry->hash_code = hash_code; 245 | entry->key = key; 246 | entry->val = val; 247 | 248 | hash_code = temp.hash_code; 249 | key = temp.key; 250 | val = temp.val; 251 | 252 | probe_current = probe_distance; 253 | } 254 | probe_current += 1; 255 | } 256 | hash_table_maybe_resize(table); 257 | } 258 | } 259 | 260 | void *hash_table_put(hash_table *table, void *key, void *val) { // Returns old val, or null 261 | assert(hash_table_is_sane(table)); 262 | unsigned long hash_code = table->hash_gen(key); 263 | return hash_table_put_int(table, key, val, hash_code); 264 | } 265 | 266 | void *hash_table_get(hash_table *table, void *key) { 267 | assert(hash_table_is_sane(table)); 268 | unsigned long hash_code = table->hash_gen(key); 269 | 270 | for (size_t i = 0; i < table->table_alloc_size; i++) { 271 | size_t table_pos = (hash_code + i) % table->table_alloc_size; 272 | struct hash_table_entry_t *entry = &table->table[table_pos]; 273 | if (hash_table_slot_is_free(entry) || i > get_distance(table, table_pos)) { 274 | break; 275 | } else if (entry->hash_code == hash_code && table->equality_test(entry->key, key)) { 276 | return entry->val; 277 | } 278 | } 279 | return NULL; 280 | } 281 | 282 | void *hash_table_remove(hash_table *table, void *key) { 283 | assert(hash_table_is_sane(table)); 284 | unsigned long hash_code = table->hash_gen(key); 285 | for (size_t i = 0; i < table->table_alloc_size; i++) { 286 | size_t table_pos = (hash_code + i) % table->table_alloc_size; 287 | struct hash_table_entry_t *entry = &table->table[table_pos]; 288 | if (hash_table_slot_is_free(entry) || i > get_distance(table, table_pos)) { 289 | assert(hash_table_is_sane(table)); 290 | return NULL; 291 | } else if (entry->hash_code == hash_code && table->equality_test(entry->key, key)) { 292 | entry->key = NO_ELEMENT; 293 | table->table_size -= 1; 294 | void *old_val = entry->val; 295 | size_t prev_pos = table_pos; 296 | for (size_t j = 1; j < table->table_alloc_size; j++) { 297 | size_t cur_pos = (table_pos + j) % table->table_alloc_size; 298 | if (hash_table_slot_is_free(&table->table[cur_pos]) ||get_distance(table, cur_pos) == 0) { 299 | table->table[prev_pos].key = NO_ELEMENT; 300 | break; 301 | } 302 | table->table[prev_pos] = table->table[cur_pos]; 303 | 304 | prev_pos = cur_pos; 305 | } 306 | hash_table_maybe_resize(table); 307 | assert(hash_table_is_sane(table)); 308 | return old_val; 309 | } 310 | } 311 | 312 | assert(hash_table_is_sane(table)); 313 | return NULL; 314 | } 315 | 316 | bool hash_table_contains(hash_table *table, void *key) { 317 | assert(hash_table_is_sane(table)); 318 | unsigned long hash_code = table->hash_gen(key); 319 | for (size_t i = 0; i < table->table_alloc_size; i++) { 320 | size_t table_pos = (hash_code + i) % table->table_alloc_size; 321 | struct hash_table_entry_t *entry = &table->table[table_pos]; 322 | if (hash_table_slot_is_free(entry)) { 323 | return false; 324 | } else if (entry->hash_code == hash_code && table->equality_test(entry->key, key)) { 325 | return true; 326 | } 327 | } 328 | return false; 329 | } 330 | 331 | size_t hash_table_size(hash_table *table) { 332 | assert(hash_table_is_sane(table)); 333 | return table->table_size; 334 | } 335 | 336 | hash_table_iter *hash_table_iter_new(hash_table *table) { 337 | assert(hash_table_is_sane(table)); 338 | hash_table_iter *to_ret = malloc_or_die(sizeof(hash_table_iter)); 339 | to_ret->table = table; 340 | to_ret->pos = 0; 341 | return to_ret; 342 | } 343 | void advance_if_necessary(hash_table_iter *iter) { 344 | while (iter->pos < iter->table->table_alloc_size && hash_table_slot_is_free(&iter->table->table[iter->pos])) 345 | iter->pos += 1; 346 | } 347 | void *hash_table_iter_key(hash_table_iter *iter) { 348 | advance_if_necessary(iter); 349 | if (iter->pos >= iter->table->table_alloc_size) 350 | return NULL; 351 | assert (!hash_table_slot_is_free(&iter->table->table[iter->pos])); 352 | return iter->table->table[iter->pos].key; 353 | } 354 | void *hash_table_iter_val(hash_table_iter *iter) { 355 | advance_if_necessary(iter); 356 | if (iter->pos >= iter->table->table_alloc_size) 357 | return NULL; 358 | assert (!hash_table_slot_is_free(&iter->table->table[iter->pos])); 359 | return iter->table->table[iter->pos].val; 360 | } 361 | bool hash_table_iter_has_cur(hash_table_iter *iter) { 362 | advance_if_necessary(iter); 363 | return (iter->pos < iter->table->table_alloc_size); 364 | } 365 | bool hash_table_iter_next(hash_table_iter *iter) { 366 | if (iter->pos >= iter->table->table_alloc_size) { 367 | assert (!hash_table_iter_has_cur(iter)); 368 | return false; 369 | } 370 | iter->pos++; 371 | return true; 372 | } 373 | 374 | 375 | void print_table(hash_table *table) { 376 | printf("["); 377 | for (size_t j = 0; j < table->table_alloc_size; j++) { 378 | if (hash_table_slot_is_free(&table->table[j])) 379 | printf("null"); 380 | else 381 | printf("%lu", table->table[j].hash_code % table->table_alloc_size); 382 | if (j != table->table_alloc_size - 1) 383 | printf(", "); 384 | } 385 | printf("]\n"); 386 | } 387 | 388 | #if 0 389 | 390 | unsigned long hash_code_int(void *long_val) { 391 | return *((unsigned long *) long_val) / 10; 392 | } 393 | 394 | bool equal_int(void *a, void *b) { 395 | return *((unsigned long *) a) == *((unsigned long *) b); 396 | } 397 | 398 | void do_iter_test(hash_table *table, unsigned long *keys, unsigned long *vals, size_t num_elems) { 399 | unsigned long *so_far_keys = NULL; 400 | unsigned long *so_far_vals = NULL; 401 | size_t num_steps = 0; 402 | for (hash_table_iter *iter = hash_table_iter_new(table); hash_table_iter_has_cur(iter); hash_table_iter_next(iter)) { 403 | so_far_vals = realloc(so_far_vals, (num_steps + 1) * sizeof(unsigned long)); 404 | assert (so_far_vals != NULL); 405 | so_far_vals[num_steps] = *(unsigned long *) hash_table_iter_val(iter); 406 | 407 | so_far_keys = realloc(so_far_keys, (num_steps + 1) * sizeof(unsigned long)); 408 | assert (so_far_keys != NULL); 409 | so_far_keys[num_steps] = *(unsigned long *) hash_table_iter_key(iter); 410 | 411 | num_steps += 1; 412 | } 413 | printf("%lu %lu\n", num_steps, num_elems); 414 | assert (num_steps == num_elems); 415 | for (size_t i = 0; i < num_steps; i++) { 416 | bool so_far_in_kv = false; 417 | bool kv_in_so_far = false; 418 | for (size_t j = 0; j < num_steps; j++) { 419 | if (keys[i] == so_far_keys[j] && vals[i] == so_far_vals[j]) 420 | kv_in_so_far = true; 421 | if (keys[j] == so_far_keys[i] && vals[j] == so_far_vals[i]) 422 | so_far_in_kv = true; 423 | } 424 | assert (so_far_in_kv); 425 | assert (kv_in_so_far); 426 | } 427 | } 428 | 429 | int main() { 430 | hash_table *table = hash_table_new(*hash_code_int, *equal_int); 431 | unsigned long *keys = NULL; 432 | unsigned long *vals = NULL; 433 | size_t num_elems = 0; 434 | char c; 435 | unsigned long *k; 436 | unsigned long *v; 437 | bool flag; 438 | while ((c = getchar()) != EOF) { 439 | switch (c) { 440 | case '+': 441 | k = malloc(sizeof(unsigned long)); 442 | if (k == NULL) 443 | return 0; 444 | if (scanf("%lu", k) <= 0) 445 | return 0; 446 | v = malloc(sizeof(unsigned long)); 447 | if (v == NULL) 448 | return 0; 449 | if (scanf("%lu", v) <= 0) 450 | return 0; 451 | printf("Adding %lu == %lu\n", *k, *v); 452 | hash_table_put(table, k, v); 453 | flag = false; 454 | for (size_t i = 0; i < num_elems; i++) { 455 | if (keys[i] == *k) { 456 | vals[i] = *v; 457 | flag = true; 458 | break; 459 | } 460 | } 461 | if (!flag) { 462 | keys = realloc(keys, (num_elems + 1) * sizeof(unsigned long)); 463 | keys[num_elems] = *k; 464 | vals = realloc(vals, (num_elems + 1) * sizeof(unsigned long)); 465 | vals[num_elems] = *v; 466 | num_elems += 1; 467 | } 468 | break; 469 | case '.': 470 | k = malloc(sizeof(long)); 471 | if (k == NULL) 472 | return 0; 473 | if (scanf("%lu", k) <= 0) 474 | return 0; 475 | printf("Getting %lu\n", *k); 476 | v = (unsigned long *) hash_table_get(table, k); 477 | flag = false; 478 | for (size_t i = 0; i < num_elems; i++) { 479 | if (keys[i] == *k) { 480 | assert (*v == vals[i]); 481 | flag = true; 482 | break; 483 | } 484 | } 485 | if (!flag) { 486 | assert (v == NULL); 487 | printf("Got %lu -> NULL\n", *k); 488 | assert(!hash_table_contains(table, k)); 489 | } else { 490 | printf("Got %lu -> %lu\n", *k, *v); 491 | assert(hash_table_contains(table, k)); 492 | } 493 | break; 494 | case '-': 495 | k = malloc(sizeof(long)); 496 | if (k == NULL) 497 | return 0; 498 | if (scanf("%lu", k) <= 0) 499 | return 0; 500 | printf("Removing %lu\n", *k); 501 | v = (unsigned long *) hash_table_remove(table, k); 502 | flag = false; 503 | for (size_t i = 0; i < num_elems; i++) { 504 | if (keys[i] == *k) { 505 | assert (*v == vals[i]); 506 | vals[i] = vals[num_elems - 1]; 507 | keys[i] = keys[num_elems - 1]; 508 | num_elems -= 1; 509 | flag = true; 510 | break; 511 | } 512 | } 513 | if (!flag) { 514 | assert (v == NULL); 515 | printf("Removed %lu -> NULL\n", *k); 516 | } else { 517 | printf("Removed %lu -> %lu\n", *k, *v); 518 | } 519 | break; 520 | case 's': 521 | k = malloc(sizeof(long)); 522 | if (k == NULL) 523 | return 0; 524 | if (scanf("%lu", k) <= 0) 525 | return 0; 526 | printf("Getting size...\n"); 527 | size_t size = hash_table_size(table); 528 | assert (size == num_elems); 529 | printf("Size: %lu\n", size); 530 | break; 531 | case 'i': 532 | do_iter_test(table, keys, vals, num_elems); 533 | break; 534 | case '\n': 535 | break; 536 | default: 537 | return 0; 538 | } 539 | } 540 | } 541 | 542 | #endif 543 | -------------------------------------------------------------------------------- /src/structures/hash_table.h: -------------------------------------------------------------------------------- 1 | #ifndef _HUO_HASH_TABLE_H 2 | #define _HUO_HASH_TABLE_H 3 | #include 4 | 5 | extern const void *NO_ELEMENT; 6 | 7 | typedef struct hash_table_t hash_table; 8 | typedef struct hash_table_iter_t hash_table_iter; 9 | 10 | typedef unsigned long (hash_code_func)(void *); 11 | typedef bool (equals_func)(void *, void *); 12 | 13 | 14 | hash_table *hash_table_new(hash_code_func *hash_gen, equals_func *equality_test); 15 | void *hash_table_put(hash_table *table, void *key, void *val); // Returns old val, or null 16 | void *hash_table_get(hash_table *table, void *key); 17 | void *hash_table_remove(hash_table *table, void *key); 18 | 19 | bool hash_table_contains(hash_table *table, void *key); 20 | size_t hash_table_size(hash_table *table); 21 | 22 | hash_table_iter *hash_table_iter_new(hash_table *table); 23 | void *hash_table_iter_key(hash_table_iter *iter); 24 | void *hash_table_iter_val(hash_table_iter *iter); 25 | bool hash_table_iter_has_cur(hash_table_iter *iter); 26 | bool hash_table_iter_next(hash_table_iter *iter); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/structures/huo_ast.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define GENERATE_AST_TYPE_ENUM_FUNCS 1 6 | #include "huo_ast.h" 7 | #undef GENERATE_AST_TYPE_ENUM_FUNCS 8 | 9 | #include "../base_util.h" 10 | 11 | struct huo_ast_t { 12 | enum ast_type_e type; 13 | size_t size; 14 | struct Value content; 15 | struct Value name; 16 | huo_ast ** children; 17 | }; 18 | 19 | huo_ast *ast_new(enum ast_type_e type, struct Value v) { 20 | struct huo_ast_t *tree = malloc_or_die(sizeof(struct huo_ast_t)); 21 | tree->type = type; 22 | tree->content = v; 23 | tree->name = v; 24 | tree->children = NULL; 25 | tree->size = 0; 26 | return tree; 27 | } 28 | enum ast_type_e ast_type(huo_ast *const tree) { 29 | assert (tree != NULL); 30 | return tree->type; 31 | } 32 | struct Value *ast_value(huo_ast *const tree) { 33 | assert (tree != NULL); 34 | return &tree->content; 35 | } 36 | void ast_set_value(huo_ast *tree, struct Value val) { 37 | tree->content = val; 38 | } 39 | void ast_push_child(huo_ast *tree, huo_ast *child) { 40 | assert (tree != NULL); 41 | assert (child != NULL); 42 | RESIZE(tree->children, tree->size + 1); 43 | tree->children[tree->size++] = child; 44 | } 45 | huo_ast *ast_pop_child(huo_ast *tree) { 46 | assert (tree != NULL); 47 | assert (ast_size(tree) != 0); 48 | huo_ast *child = ast_child(tree, ast_size(tree) - 1); 49 | RESIZE(tree->children, tree->size - 1); 50 | return child; 51 | } 52 | huo_ast *ast_child(huo_ast *tree, size_t i) { 53 | assert (i < ast_size(tree)); 54 | return tree->children[i]; 55 | } 56 | void ast_set_child(huo_ast *tree, size_t i, huo_ast *child) { 57 | assert (i < ast_size(tree)); 58 | tree->children[i] = child; 59 | } 60 | size_t ast_size(huo_ast *const tree) { 61 | return tree->size; 62 | } 63 | 64 | struct String *ast_to_string_indent(huo_ast *const tree, size_t indent); 65 | 66 | struct String *ast_print_wrap(huo_ast *const tree, size_t indent, char *sep, char *start, char *end) { 67 | // Formats like this: 68 | 69 | // ("a" 70 | // 2 71 | // 3 72 | // "qwert") 73 | 74 | // or 75 | // ( ) 76 | 77 | struct String st = string_from_chars(start); 78 | struct String *s = string_copy_heap(&st); 79 | if (ast_size(tree) > 0) { 80 | string_concat_to(s, ast_to_string_indent(ast_child(tree, 0), indent + 1)); 81 | for (size_t i = 1; i < ast_size(tree); i++) { 82 | huo_ast *child = ast_child(tree, i); 83 | string_concat_to_chars(s, sep); 84 | string_concat_to_chars(s, "\n"); 85 | for (size_t j = 0; j < indent; j++) { 86 | string_concat_to_chars(s, " "); 87 | } 88 | string_concat_to(s, ast_to_string_indent(child, indent + 1)); 89 | } 90 | } else { 91 | string_concat_to_chars(s, " "); 92 | } 93 | string_concat_to_chars(s, end); 94 | return s; 95 | } 96 | 97 | struct String *ast_to_string_indent(huo_ast *const tree, size_t indent) { 98 | 99 | struct String st = string_from_chars(""); 100 | struct String *s = string_copy_heap(&st); 101 | struct String val_str; 102 | switch (tree->type) { 103 | case AST_STATEMENT: 104 | string_concat_to(s, ast_print_wrap(tree, indent, "", "(", ")")); 105 | break; 106 | case AST_ARRAY: 107 | string_concat_to(s, ast_print_wrap(tree, indent, ",", "[", "]")); 108 | break; 109 | case AST_FLOAT: 110 | string_concat_to_float(s, value_as_float(ast_value(tree))); 111 | break; 112 | case AST_INTEGER: 113 | string_concat_to_long(s, value_as_long(ast_value(tree))); 114 | break; 115 | case AST_BOOLEAN: 116 | string_concat_to_chars(s, value_as_bool(ast_value(tree)) ? "true" : "false"); 117 | break; 118 | case AST_STRING: 119 | string_concat_to_chars(s, "\""); 120 | val_str = value_as_string(ast_value(tree)); 121 | string_concat_to(s, &val_str); 122 | string_concat_to_chars(s, "\""); 123 | break; 124 | case AST_KEYWORD: 125 | val_str = value_as_keyword(&tree->name); 126 | string_concat_to(s, &val_str); 127 | break; 128 | default: 129 | ERROR("Unknown type: %c", tree->type); 130 | } 131 | return s; 132 | } 133 | struct String *ast_to_string(huo_ast *const tree) { 134 | return ast_to_string_indent(tree, 0); 135 | } 136 | 137 | 138 | huo_ast *ast_copy(huo_ast *const from) { 139 | huo_ast *ast = malloc_or_die(sizeof(struct huo_ast_t)); 140 | ast->type = from->type; 141 | ast->content = value_copy_stack(&from->content); 142 | ast->name = value_copy_stack(&from->name); 143 | ast->children = NULL; 144 | ast->size = from->size; 145 | RESIZE(ast->children, from->size); 146 | for(size_t i = 0; i < from->size; i++){ 147 | ast->children[i] = ast_copy(from->children[i]); 148 | } 149 | return ast; 150 | } 151 | 152 | void ast_copy_to(huo_ast *to, huo_ast *const from) { 153 | to->type = from->type; 154 | value_copy_to(&to->content, &from->content); 155 | 156 | for(size_t i = to->size; i < from->size; i++){ 157 | ast_free(to->children[i]); 158 | } 159 | 160 | RESIZE(to->children, from->size); 161 | to->size = from->size; 162 | for(size_t i = 0; i < from->size; i++){ 163 | ast_copy_to(to->children[i], from->children[i]); 164 | } 165 | 166 | } 167 | 168 | void ast_free(huo_ast *ast) { 169 | if (ast != NULL) { 170 | value_free(ast_value(ast)); 171 | if (ast->children != NULL) { 172 | for(size_t i = 0; i < ast->size; i++){ 173 | ast_free(ast_child(ast, i)); 174 | } 175 | free(ast->children); 176 | } 177 | free(ast); 178 | } 179 | } 180 | 181 | huo_ast * value_as_ast(struct Value *v) { 182 | CHECK_TYPE(v, TYPE_AST); 183 | return v->data.ast; 184 | } 185 | 186 | struct Value value_from_ast(huo_ast *ast) { 187 | struct Value v = { 188 | .type = TYPE_AST, 189 | .data.ast = ast 190 | }; 191 | return v; 192 | } 193 | -------------------------------------------------------------------------------- /src/structures/huo_ast.h: -------------------------------------------------------------------------------- 1 | #ifndef AST_H 2 | #define AST_H 1 3 | 4 | #include 5 | #include 6 | 7 | typedef struct huo_ast_t huo_ast; 8 | 9 | #include "value.h" 10 | 11 | enum ast_type_e { 12 | AST_STATEMENT, 13 | AST_ARRAY, 14 | AST_FLOAT, 15 | AST_INTEGER, 16 | AST_BOOLEAN, 17 | AST_STRING, 18 | AST_KEYWORD, 19 | }; 20 | 21 | huo_ast * value_as_ast(struct Value *v); 22 | struct Value value_from_ast(huo_ast *ast); 23 | 24 | huo_ast *ast_new(enum ast_type_e type, struct Value v); 25 | enum ast_type_e ast_type(huo_ast *const tree); 26 | struct Value *ast_value(huo_ast *const tree); 27 | void ast_set_value(huo_ast *tree, struct Value val); 28 | void ast_push_child(huo_ast *tree, huo_ast *child); 29 | huo_ast *ast_pop_child(huo_ast *tree); 30 | huo_ast *ast_child(huo_ast *tree, size_t i); 31 | void ast_set_child(huo_ast *tree, size_t i, huo_ast *child); 32 | size_t ast_size(huo_ast *const tree); 33 | struct String *ast_to_string(huo_ast *const tree); 34 | 35 | huo_ast *ast_copy(huo_ast *const from); 36 | void ast_copy_to(huo_ast *to, huo_ast *const from); 37 | 38 | void ast_free(huo_ast *ast); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/structures/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../base_util.h" 6 | #include 7 | #include "string.h" 8 | #include "../config.h" 9 | #include "value.h" 10 | 11 | 12 | bool string_is_sane(const struct String *const s) { 13 | assert (s != NULL); 14 | assert(s->length == 0 || s->body != NULL); 15 | assert(s->length == 0 || s->body[s->length] == 0); 16 | return true; 17 | } 18 | 19 | struct String string_from_char(char c) { 20 | struct String s = { 21 | .length = 1, 22 | .body = ARR_MALLOC(2, char) 23 | }; 24 | s.body[0] = c; 25 | s.body[1] = 0; 26 | assert(string_is_sane(&s)); 27 | return s; 28 | } 29 | 30 | struct String string_from_chars(const char *str) { 31 | struct String s; 32 | if (str == NULL) { 33 | s.length = 0; 34 | s.body = NULL; 35 | } else { 36 | int l = strlen(str); 37 | s.length = l; 38 | s.body = ARR_MALLOC(l + 1, char); 39 | strcpy(s.body, str); 40 | s.body[s.length] = 0; 41 | } 42 | assert(string_is_sane(&s)); 43 | return s; 44 | } 45 | 46 | struct String string_concat_stack(struct String *a, struct String *b) { 47 | struct String temp = string_copy_stack(a); 48 | string_concat_to(&temp, b); 49 | return temp; 50 | } 51 | 52 | struct String *string_concat_heap(struct String *a, struct String *b) { 53 | struct String *temp = string_copy_heap(a); 54 | string_concat_to(temp, b); 55 | return temp; 56 | } 57 | 58 | void string_concat_to(struct String *to, struct String *from) { 59 | assert(string_is_sane(from)); 60 | assert(string_is_sane(to)); 61 | int len = to->length; 62 | to->length += from->length; 63 | RESIZE(to->body, to->length + 1); 64 | for(size_t l = 0; l < from->length; l++){ 65 | to->body[l+len] = from->body[l]; 66 | } 67 | to->body[to->length] = 0; 68 | assert(string_is_sane(from)); 69 | assert(string_is_sane(to)); 70 | } 71 | 72 | void string_concat_to_consume(struct String *to, struct String s) { 73 | string_concat_to(to, &s); 74 | string_free(&s); 75 | } 76 | 77 | void string_concat_to_chars(struct String *to, char *from) { 78 | assert(string_is_sane(to)); 79 | int len = to->length; 80 | size_t from_length = strlen(from); 81 | to->length += from_length; 82 | RESIZE(to->body, to->length + 1); 83 | for(size_t l = 0; l < from_length; l++){ 84 | to->body[l+len] = from[l]; 85 | } 86 | to->body[to->length] = 0; 87 | assert(string_is_sane(to)); 88 | } 89 | void string_concat_to_long(struct String *to, huo_int_t from) { 90 | assert(string_is_sane(to)); 91 | 92 | size_t int_size = snprintf(NULL, 0, "%"PRIhi, from); 93 | 94 | int len = to->length; 95 | to->length += int_size; 96 | RESIZE(to->body, to->length + 1); 97 | sprintf(&to->body[len], "%"PRIhi, from); 98 | assert(string_is_sane(to)); 99 | } 100 | void string_concat_to_float(struct String *to, float from) { 101 | assert(string_is_sane(to)); 102 | 103 | size_t int_size = snprintf(NULL, 0, "%f", from); 104 | 105 | int len = to->length; 106 | to->length += int_size; 107 | RESIZE(to->body, to->length + 1); 108 | sprintf(&to->body[len], "%f", from); 109 | assert(string_is_sane(to)); 110 | } 111 | 112 | bool string_contains(char ch, const struct String* string){ 113 | assert(string_is_sane(string)); 114 | if(!string->length){ return false; } 115 | for(size_t i = 0; i < string->length; i++){ 116 | if(ch == string->body[i]){ 117 | assert(string_is_sane(string)); 118 | return true; 119 | } 120 | } 121 | assert(string_is_sane(string)); 122 | return false; 123 | } 124 | 125 | struct String string_copy_stack(struct String *from) { 126 | assert(string_is_sane(from)); 127 | struct String s = { 128 | .length = 0, 129 | .body = NULL 130 | }; 131 | string_copy_to(&s, from); 132 | assert(string_is_sane(&s)); 133 | return s; 134 | } 135 | 136 | struct String *string_copy_heap(struct String *from) { 137 | assert(string_is_sane(from)); 138 | struct String *s = malloc_or_die(sizeof(struct String)); 139 | s->length = 0; 140 | s->body = NULL; 141 | string_copy_to(s, from); 142 | assert(string_is_sane(s)); 143 | return s; 144 | } 145 | 146 | void string_copy_to(struct String *to, struct String *from) { 147 | assert(string_is_sane(from)); 148 | assert(string_is_sane(to)); 149 | if (from->length == 0) { 150 | RESIZE(to->body, 0); 151 | to->length = 0; 152 | } else { 153 | if (to->length != from->length) { 154 | RESIZE(to->body, from->length + 1); // 0 byte at end 155 | to->length = from->length; 156 | } 157 | strcpy(to->body, from->body); 158 | } 159 | assert(string_is_sane(from)); 160 | assert(string_is_sane(to)); 161 | } 162 | 163 | bool string_matches_stack(struct String base, struct String compare) { 164 | return string_matches_heap(&base, &compare); 165 | } 166 | 167 | bool string_matches_heap(struct String *base, struct String *compare){ 168 | assert(string_is_sane(base)); 169 | assert(string_is_sane(compare)); 170 | if(base->length != compare->length){ 171 | return false; 172 | } 173 | size_t counter = 0; 174 | while(counter < base->length){ 175 | if(base->body[counter] != compare->body[counter]){ 176 | return false; 177 | } 178 | counter++; 179 | } 180 | return true; 181 | } 182 | bool string_matches_char(struct String *base, char c) { 183 | assert(string_is_sane(base)); 184 | return (base->length == 1 && base->body[0] == c); 185 | } 186 | 187 | char *string_to_chars(const struct String *s) { 188 | assert(string_is_sane(s)); 189 | if (s->length == 0) { 190 | return ""; 191 | } 192 | return s->body; 193 | } 194 | size_t string_length(struct String *s) { 195 | assert(string_is_sane(s)); 196 | return s->length; 197 | } 198 | char string_index(struct String *s, size_t i) { 199 | assert(string_is_sane(s)); 200 | if (i >= s->length) { 201 | ERROR("Index out of range: %zu >= %zu", i, s->length); 202 | } 203 | return s->body[i]; 204 | } 205 | 206 | unsigned long string_hash_code(struct String *s) { 207 | // djb2 208 | unsigned long hash = 5381; 209 | if (s->length == 0) 210 | return hash; 211 | 212 | char *pos = s->body; 213 | 214 | while (*pos != 0) 215 | hash = hash * 33 + *(pos++); 216 | 217 | return hash; 218 | } 219 | unsigned long string_hash_code_vv(void *s) { 220 | return string_hash_code((struct String *) s); 221 | } 222 | 223 | bool string_matches_vv(void *base, void *compare) { 224 | return string_matches_heap((struct String *) base, (struct String *) compare); 225 | } 226 | 227 | void string_free_stack(struct String s) { 228 | if (s.body != NULL) { 229 | free(s.body); 230 | s.body = NULL; 231 | } 232 | s.length = 0; 233 | } 234 | 235 | void string_free(struct String *const s) { 236 | if (s != NULL) { 237 | string_free_stack(*s); 238 | free(s); 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/structures/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _HUO_STRING_H 2 | #define _HUO_STRING_H 3 | #include 4 | #include 5 | #include 6 | #include "../config.h" 7 | // _STRING_H already exists! 8 | 9 | struct String { 10 | size_t length; 11 | char *body; 12 | }; 13 | 14 | /* C compile-time constant madness*/ 15 | #define STRLEN(s) ( (sizeof(s)/sizeof(s[0])) - sizeof(s[0]) ) 16 | #define STR_NEW(str)\ 17 | {\ 18 | .length = STRLEN(str),\ 19 | .body=(str)\ 20 | } 21 | 22 | struct String string_from_char(char c); 23 | struct String string_from_chars(const char *str); 24 | bool string_is_sane(const struct String *const s); 25 | struct String string_copy_stack(struct String *from); 26 | struct String *string_copy_heap(struct String *from); 27 | void string_copy_to(struct String *to, struct String *from); 28 | struct String string_concat_stack(struct String *a, struct String *b); 29 | struct String *string_concat_heap(struct String *a, struct String *b); 30 | void string_concat_to(struct String *to, struct String *from); 31 | void string_concat_to_consume(struct String *to, struct String s); 32 | void string_concat_to_chars(struct String *to, char *from); 33 | void string_concat_to_long(struct String *to, huo_int_t from); 34 | void string_concat_to_float(struct String *to, float from); 35 | bool string_matches_heap(struct String *base, struct String *compare); 36 | bool string_matches_char(struct String *base, char c); 37 | bool string_matches_stack(struct String base, struct String compare); 38 | char *string_to_chars(const struct String *s); 39 | size_t string_length(struct String *s); 40 | char string_index(struct String *s, size_t i); 41 | bool string_contains(char ch, const struct String* string); 42 | 43 | unsigned long string_hash_code(struct String *s); 44 | unsigned long string_hash_code_vv(void *s); 45 | 46 | bool string_matches_vv(void *base, void *compare); 47 | 48 | void string_free(struct String *const string); 49 | void string_free_stack(struct String string); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/structures/structures.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRUCTURES_H 2 | #define _STRUCTURES_H 3 | 4 | #include 5 | 6 | #include "string.h" 7 | #include "value.h" 8 | #include "huo_ast.h" 9 | #include "array.h" 10 | #include "hash_table.h" 11 | #include "token.h" 12 | 13 | struct Scopes { 14 | hash_table ** scopes; 15 | size_t size; 16 | size_t current; 17 | }; 18 | 19 | struct Execution_bundle { 20 | huo_ast *ast; 21 | struct Scopes *scopes; 22 | huo_depth_t max_depth; 23 | }; 24 | 25 | struct definition { 26 | bool is_func; 27 | union { 28 | struct Value *val; 29 | huo_ast *ast; 30 | } val; 31 | }; 32 | 33 | #endif /* _STRUCTURES_H */ 34 | -------------------------------------------------------------------------------- /src/structures/token.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "string.h" 4 | #include "../base_util.h" 5 | 6 | #define GENERATE_TOKEN_TYPE_ENUM_FUNCS 1 7 | #include "token.h" 8 | #undef GENERATE_TOKEN_TYPE_ENUM_FUNCS 9 | 10 | 11 | 12 | bool char_is_digit(char c) { 13 | // By the C standard, 0-9 is guarinteed to be contigous. 14 | return c >= '0' && c <= '9'; 15 | } 16 | 17 | static const struct String word_chars = STR_NEW("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); 18 | bool char_is_word(char c) { 19 | return string_contains(c, &word_chars); 20 | } 21 | 22 | bool can_be_extended(struct String so_far, char cur, enum token_type_t type) { 23 | switch (type) { 24 | case TOK_PLUS: 25 | case TOK_MINUS: 26 | case TOK_BUILTIN: 27 | case TOK_DOT: 28 | case TOK_COMMA: 29 | case TOK_OPEN_BRACKET: 30 | case TOK_CLOSE_BRACKET: 31 | case TOK_OPEN_SQUARE: 32 | case TOK_CLOSE_SQUARE: 33 | return false; 34 | case TOK_WHITESPACE: 35 | case TOK_NEWLINE: 36 | case TOK_NUMBER: 37 | case TOK_WORD: 38 | return can_be_of_type(cur, type); 39 | case TOK_QUOTE: 40 | // I.e. "not a newline" and "prev char, if not the starting quote, not a quote" 41 | return (so_far.length <= 1 || !can_be_of_type(so_far.body[so_far.length - 1], TOK_QUOTE)) && !can_be_of_type(cur, TOK_NEWLINE); 42 | case TOK_COMMENT: 43 | return !can_be_of_type(cur, TOK_NEWLINE); 44 | default: 45 | ERROR("Unknown type: '%d'", type); 46 | } 47 | } 48 | 49 | bool can_be_of_type(char c, enum token_type_t type) { 50 | if (c == 0) { 51 | return type == TOK_EOF; 52 | } 53 | switch (type) { 54 | case TOK_WHITESPACE: 55 | return c == ' ' || c == '\t' || c == '\r'; 56 | case TOK_NEWLINE: 57 | return c == '\n'; 58 | case TOK_PLUS: 59 | return c == '+'; 60 | case TOK_MINUS: 61 | return c == '-'; 62 | case TOK_BUILTIN: 63 | return c == '&' || c == '|' || c == '*' || c == '/' || c == '!' || c == '=' || c == '<' || c == '>'; 64 | case TOK_NUMBER: 65 | return char_is_digit(c); 66 | case TOK_DOT: 67 | return c == '.'; 68 | case TOK_COMMA: 69 | return c == ','; 70 | case TOK_WORD: 71 | return char_is_word(c); 72 | case TOK_OPEN_BRACKET: 73 | return c == '('; 74 | case TOK_CLOSE_BRACKET: 75 | return c == ')'; 76 | case TOK_OPEN_SQUARE: 77 | return c == '['; 78 | case TOK_CLOSE_SQUARE: 79 | return c == ']'; 80 | case TOK_QUOTE: 81 | return c == '"'; 82 | case TOK_COMMENT: 83 | return c == ';'; 84 | default: 85 | printf("%i", c); 86 | ERROR("Unknown type: '%d'", type); 87 | } 88 | } 89 | 90 | enum token_type_t get_token_type(char c) { 91 | for (size_t i = 0; i < enum_len_token_type_t(); i++) { 92 | enum token_type_t type = enum_iter_token_type_t(i); 93 | if (can_be_of_type(c, type)) { 94 | return type; 95 | } 96 | } 97 | ERROR("Unknown character: '%c' = '%d'", c, c); 98 | } 99 | -------------------------------------------------------------------------------- /src/structures/token.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Here be dragons. 5 | 6 | // Basic idea: 7 | // Header includes itself 3x if GENERATE_TOKEN_TYPE_ENUM_FUNCS 8 | // Once to do the enum definition 9 | // Once to do the enum->string mapping 10 | // Once to do the enum iterator. 11 | 12 | #if GENERATE_TOKEN_TYPE_ENUM_FUNCS 13 | #if GENERATED_TOKEN_TYPE_ENUM_FUNCS 14 | #error "Generating token type enum functions in multiple places!" 15 | #endif 16 | 17 | #undef GENERATE_TOKEN_TYPE_ENUM_FUNCS 18 | #include "token.h" 19 | 20 | #define GENERATE_ENUM_STRINGS 1 21 | #include "token.h" 22 | #undef GENERATE_ENUM_STRINGS 23 | 24 | #define GENERATE_ENUM_ITER 1 25 | #include "token.h" 26 | #undef GENERATE_ENUM_ITER 27 | 28 | #define GENERATED_TOKEN_TYPE_ENUM_FUNCS 1 29 | #endif 30 | 31 | #undef USE_HEADER_GUARD 32 | #if GENERATE_ENUM_STRINGS 33 | #define DECL_ENUM_ELEMENT(ELEMENT) #ELEMENT 34 | #define BEGIN_ENUM(ENUM_NAME) static const char* enum_names_##ENUM_NAME [] = 35 | #define END_ENUM(ENUM_NAME) ; \ 36 | const char* enum_name_##ENUM_NAME(enum ENUM_NAME index){\ 37 | return enum_names_##ENUM_NAME [index];\ 38 | } 39 | #elif GENERATE_ENUM_ITER 40 | #define DECL_ENUM_ELEMENT(ELEMENT) ELEMENT 41 | #define BEGIN_ENUM(ENUM_NAME) static const enum ENUM_NAME enum_iters_##ENUM_NAME [] = 42 | #define END_ENUM(ENUM_NAME) ; \ 43 | enum ENUM_NAME enum_iter_##ENUM_NAME(enum ENUM_NAME index){\ 44 | return enum_iters_##ENUM_NAME [index];\ 45 | } \ 46 | size_t enum_len_##ENUM_NAME() {return sizeof(enum_iters_##ENUM_NAME) / sizeof(enum_iters_##ENUM_NAME[0]);} 47 | #else 48 | #define USE_HEADER_GUARD 1 49 | #define DECL_ENUM_ELEMENT(ELEMENT) ELEMENT 50 | #define BEGIN_ENUM(ENUM_NAME) enum ENUM_NAME 51 | #define END_ENUM(ENUM_NAME) ; \ 52 | const char* enum_name_##ENUM_NAME(enum ENUM_NAME index); \ 53 | enum ENUM_NAME enum_iter_##ENUM_NAME(enum ENUM_NAME index); \ 54 | size_t enum_len_##ENUM_NAME(); 55 | #endif 56 | 57 | #if !USE_HEADER_GUARD || !TOKEN_TYPE_DEC 58 | 59 | #if USE_HEADER_GUARD 60 | #define TOKEN_TYPE_DEC 1 61 | #endif 62 | 63 | BEGIN_ENUM(token_type_t) { 64 | DECL_ENUM_ELEMENT(TOK_WHITESPACE), // " \t" 65 | DECL_ENUM_ELEMENT(TOK_NEWLINE), // "\n" 66 | DECL_ENUM_ELEMENT(TOK_PLUS), // "+" 67 | DECL_ENUM_ELEMENT(TOK_MINUS), // "-" 68 | DECL_ENUM_ELEMENT(TOK_BUILTIN), // [*\!=<>&|] 69 | DECL_ENUM_ELEMENT(TOK_NUMBER), // [0-9]+ 70 | DECL_ENUM_ELEMENT(TOK_DOT), // "." 71 | DECL_ENUM_ELEMENT(TOK_COMMA), // "," 72 | DECL_ENUM_ELEMENT(TOK_WORD), // [_a-zA-Z]+ 73 | DECL_ENUM_ELEMENT(TOK_OPEN_BRACKET), // "(" 74 | DECL_ENUM_ELEMENT(TOK_CLOSE_BRACKET), // ")" 75 | DECL_ENUM_ELEMENT(TOK_OPEN_SQUARE), // "[" 76 | DECL_ENUM_ELEMENT(TOK_CLOSE_SQUARE), // "]" 77 | DECL_ENUM_ELEMENT(TOK_QUOTE), // """ 78 | DECL_ENUM_ELEMENT(TOK_COMMENT), // ";" 79 | DECL_ENUM_ELEMENT(TOK_EOF) // end of file 80 | } END_ENUM(token_type_t) 81 | 82 | #endif 83 | 84 | #undef DECL_ENUM_ELEMENT 85 | #undef BEGIN_ENUM 86 | #undef END_ENUM 87 | 88 | #ifndef _TOKEN_H 89 | #define _TOKEN_H 1 90 | 91 | struct Token { 92 | enum token_type_t type; 93 | struct String data; 94 | }; 95 | 96 | struct Tokens { 97 | struct Token *tokens; 98 | size_t length; 99 | size_t counter; 100 | }; 101 | 102 | bool can_be_extended(struct String so_far, char cur, enum token_type_t type); 103 | 104 | bool can_be_of_type(char c, enum token_type_t type); 105 | 106 | enum token_type_t get_token_type(char c); 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/structures/tokens.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuoLanguage/huo/66394147a034d89e48aff394166d7afe62c21cf6/src/structures/tokens.c -------------------------------------------------------------------------------- /src/structures/tokens.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuoLanguage/huo/66394147a034d89e48aff394166d7afe62c21cf6/src/structures/tokens.h -------------------------------------------------------------------------------- /src/structures/value.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "structures.h" 3 | #include "../constants.h" 4 | #include "value.h" 5 | #include "../base_util.h" 6 | #include "../config.h" 7 | 8 | struct Value value_copy_stack(struct Value * b){ 9 | struct Value a; 10 | if (b->type == TYPE_STRING || b->type == TYPE_KEYWORD) { 11 | a.data.str = value_as_string_or_kwd(b); 12 | } else if(b->type == TYPE_FLOAT){ 13 | a.data.fl = value_as_float(b); 14 | } else if(b->type == TYPE_LONG){ 15 | a.data.ln = value_as_long(b); 16 | } else if (b->type == TYPE_BOOL){ 17 | a.data.bl = value_as_bool(b); 18 | } else if (b->type == TYPE_ARRAY){ 19 | a.data.array = array_copy_heap(value_as_array(b)); 20 | } else if (b->type == TYPE_UNDEF){ 21 | a.type = TYPE_UNDEF; 22 | } else { 23 | ERROR("Unknown type: %c", a.type); 24 | } 25 | a.type = b->type; 26 | return a; 27 | } 28 | 29 | struct Value *value_copy_heap(struct Value * b){ 30 | struct Value *a = malloc_or_die(sizeof(struct Value)); 31 | if (b->type == TYPE_STRING || b->type == TYPE_KEYWORD) { 32 | a->data.str = value_as_string_or_kwd(b); 33 | } else if(b->type == TYPE_FLOAT){ 34 | a->data.fl = value_as_float(b); 35 | } else if(b->type == TYPE_LONG){ 36 | a->data.ln = value_as_long(b); 37 | } else if (b->type == TYPE_BOOL){ 38 | a->data.bl = value_as_bool(b); 39 | } else if (b->type == TYPE_ARRAY){ 40 | a->data.array = array_copy_heap(value_as_array(b)); 41 | } else if (b->type == TYPE_AST){ 42 | a->data.ast = ast_copy(value_as_ast(b)); 43 | } else if (b->type == TYPE_UNDEF){ 44 | a->type = TYPE_UNDEF; 45 | } else { 46 | ERROR("Unknown type: %c", a->type); 47 | } 48 | a->type = b->type; 49 | return a; 50 | } 51 | 52 | void value_copy_to(struct Value * a, struct Value * b){ 53 | #if 0 54 | if (a->type == TYPE_STRING) { 55 | string_free(value_as_string(a)); 56 | } else if (a->type == TYPE_KEYWORD) { 57 | string_free(value_as_keyword(a)); 58 | }else if (a->type == TYPE_ARRAY) { 59 | array_free(value_as_array(a)); 60 | } 61 | #endif 62 | if(b->type == TYPE_STRING || b->type == TYPE_KEYWORD){ 63 | struct String b_str = value_as_string_or_kwd(b); 64 | string_copy_to(&a->data.str, &b_str); 65 | } else if(b->type == TYPE_FLOAT){ 66 | a->data.fl = value_as_float(b); 67 | } else if(b->type == TYPE_LONG){ 68 | a->data.ln = value_as_long(b); 69 | } else if (b->type == TYPE_BOOL){ 70 | a->data.bl = value_as_bool(b); 71 | } else if (b->type == TYPE_ARRAY){ 72 | array_copy_to(value_as_array(a), value_as_array(b)); 73 | } else if (b->type == TYPE_UNDEF){ 74 | // a->type == TYPE_UNDEF; 75 | } else { 76 | ERROR("Unknown type: %c", a->type); 77 | } 78 | a->type = b->type; 79 | } 80 | 81 | float value_as_float(struct Value *v) { 82 | if(v->type == TYPE_LONG){ 83 | return (float)v->data.ln; 84 | } else { 85 | CHECK_TYPE(v, TYPE_FLOAT); 86 | return v->data.fl; 87 | } 88 | } 89 | bool value_as_bool(struct Value *v) { 90 | CHECK_TYPE(v, TYPE_BOOL); 91 | return v->data.bl; 92 | } 93 | huo_int_t value_as_long(struct Value *v) { 94 | if(v->type == TYPE_FLOAT){ 95 | return (long)v->data.fl; 96 | } else { 97 | CHECK_TYPE(v, TYPE_LONG); 98 | return v->data.ln; 99 | } 100 | } 101 | struct String value_as_string_or_kwd(struct Value *v) { 102 | if (v->type == TYPE_STRING) { 103 | return value_as_string(v); 104 | } else if (v->type == TYPE_KEYWORD) { 105 | return value_as_keyword(v); 106 | } else { 107 | ERROR("Unknown type: %c", v->type); 108 | } 109 | } 110 | struct String value_as_string(struct Value *v) { 111 | CHECK_TYPE(v, TYPE_STRING); 112 | return v->data.str; 113 | } 114 | struct Value_array *value_as_array(struct Value *v) { 115 | CHECK_TYPE(v, TYPE_ARRAY); 116 | return v->data.array; 117 | } 118 | struct String value_as_keyword(struct Value *v) { 119 | CHECK_TYPE(v, TYPE_KEYWORD); 120 | return v->data.str; 121 | } 122 | 123 | size_t length(struct Value a); 124 | 125 | struct Value value_from_float(float f) { 126 | struct Value v = { 127 | .type = TYPE_FLOAT, 128 | .data.fl = f 129 | }; 130 | return v; 131 | } 132 | 133 | struct Value value_from_bool(bool b) { 134 | struct Value v = { 135 | .type = TYPE_BOOL, 136 | .data.bl = b 137 | }; 138 | return v; 139 | } 140 | 141 | struct Value value_from_long(huo_int_t l) { 142 | struct Value v = { 143 | .type = TYPE_LONG, 144 | .data.ln = l 145 | }; 146 | return v; 147 | } 148 | 149 | struct Value value_from_string(struct String str) { 150 | struct Value v = { 151 | .type = TYPE_STRING, 152 | .data.str = str 153 | }; 154 | return v; 155 | } 156 | 157 | struct Value value_from_array(struct Value_array *arr) { 158 | struct Value v = { 159 | .type = TYPE_ARRAY, 160 | .data.array = arr 161 | }; 162 | return v; 163 | } 164 | 165 | struct Value value_from_keyword(struct String *kwd) { 166 | struct Value v = { 167 | .type = TYPE_KEYWORD, 168 | .data.str = *kwd 169 | }; 170 | return v; 171 | } 172 | struct Value value_from_undef() { 173 | struct Value v = { 174 | .type = TYPE_UNDEF, 175 | }; 176 | return v; 177 | } 178 | 179 | size_t length(struct Value a) { 180 | if (a.type == TYPE_STRING) { 181 | return string_length(&a.data.str); 182 | } else if (a.type == TYPE_ARRAY) { 183 | return a.data.array->size; 184 | } else { 185 | ERROR("Type error: value of type '%c' has no length property", a.type); 186 | } 187 | } 188 | 189 | unsigned long value_keyword_hash_code(void *value) { 190 | struct String word = value_as_keyword((struct Value *) value); 191 | return string_hash_code(&word); 192 | } 193 | bool value_keyword_equality(void *a, void *b) { 194 | struct String aword = value_as_keyword((struct Value *) a); 195 | struct String bword = value_as_keyword((struct Value *) b); 196 | return string_matches_heap(&aword, &bword); 197 | } 198 | 199 | 200 | bool value_equals_shallow(struct Value *a, struct Value *b) { 201 | if (a->type != b->type) 202 | return false; 203 | switch (a->type) { 204 | case TYPE_ARRAY: 205 | return value_as_array(a) == value_as_array(b); 206 | case TYPE_STRING: 207 | return string_matches_stack(value_as_string(a), value_as_string(b)); 208 | case TYPE_LONG: 209 | return value_as_long(a) == value_as_long(b); 210 | case TYPE_FLOAT: 211 | return value_as_float(a) == value_as_float(b); 212 | case TYPE_BOOL: 213 | return value_as_bool(a) == value_as_bool(b); 214 | case TYPE_KEYWORD: 215 | return string_matches_stack(value_as_keyword(a), value_as_keyword(b)); 216 | default: 217 | ERROR("Unknown type %i", a->type); 218 | } 219 | } 220 | 221 | void value_negate(struct Value *v) { 222 | if(v->type == TYPE_FLOAT){ 223 | v->data.fl = -value_as_float(v); 224 | } else if(v->type == TYPE_LONG){ 225 | v->data.ln = -value_as_long(v); 226 | } else { 227 | ERROR("Type error: value of type '%c' cannot be negated", v->type); 228 | } 229 | } 230 | 231 | struct String type_to_string(enum Value_type type){ 232 | switch (type) { 233 | case TYPE_STRING: 234 | return string_copy_stack(&string_const); 235 | break; 236 | case TYPE_FLOAT: 237 | case TYPE_LONG: 238 | return string_copy_stack(&number_const); 239 | break; 240 | case TYPE_ARRAY: 241 | return string_copy_stack(&array_const); 242 | break; 243 | case TYPE_BOOL: 244 | return string_copy_stack(&boolean_const); 245 | break; 246 | case TYPE_KEYWORD: 247 | return string_copy_stack(&keyword_const); 248 | break; 249 | case TYPE_UNDEF: 250 | return string_copy_stack(&undefined_const); 251 | break; 252 | default: 253 | ERROR("Type error: unrecognized type: '%c'.", type) 254 | } 255 | } 256 | 257 | void value_free_stack(struct Value v) { 258 | switch (v.type) { 259 | case TYPE_ARRAY: 260 | array_free(v.data.array); 261 | break; 262 | case TYPE_STRING: 263 | case TYPE_KEYWORD: 264 | string_free_stack(v.data.str); 265 | break; 266 | case TYPE_LONG: 267 | case TYPE_FLOAT: 268 | case TYPE_BOOL: 269 | case TYPE_UNDEF: 270 | break; 271 | default: 272 | ERROR("Unknown type %i", v.type); 273 | } 274 | v.type = TYPE_UNDEF; 275 | } 276 | 277 | void value_free(struct Value *v) { 278 | if (v != NULL) { 279 | value_free_stack(*v); 280 | free(v); 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /src/structures/value.h: -------------------------------------------------------------------------------- 1 | #ifndef _VALUE_H 2 | #define _VALUE_H 3 | 4 | #include 5 | #include "structures.h" 6 | #include "string.h" 7 | 8 | enum Value_type { 9 | TYPE_FLOAT, 10 | TYPE_BOOL, 11 | TYPE_LONG, 12 | TYPE_STRING, 13 | TYPE_ARRAY, 14 | TYPE_KEYWORD, 15 | TYPE_AST, 16 | TYPE_UNDEF 17 | }; 18 | 19 | typedef struct huo_ast_t huo_ast; 20 | 21 | union Data { 22 | bool bl; 23 | huo_int_t ln; 24 | float fl; 25 | struct String str; 26 | struct Value_array * array; 27 | huo_ast * ast; 28 | }; 29 | 30 | struct Value { 31 | enum Value_type type; 32 | union Data data; 33 | }; 34 | 35 | #define CHECK_TYPE(v, tp) do {\ 36 | /* assert((v)->type == (tp)); */ \ 37 | if ((v)->type != (tp))\ 38 | ERROR("Invalid type: '%i' != '%i'", (v)->type, (tp));\ 39 | } while (0) 40 | 41 | float value_as_float(struct Value *v); 42 | bool value_as_bool(struct Value *v); 43 | huo_int_t value_as_long(struct Value *v); 44 | struct String value_as_string_or_kwd(struct Value *v); 45 | struct String value_as_string(struct Value *v); 46 | struct Value_array *value_as_array(struct Value *v); 47 | struct String value_as_keyword(struct Value *v); 48 | 49 | struct Value value_from_float(float f); 50 | struct Value value_from_bool(bool b); 51 | struct Value value_from_long(huo_int_t l); 52 | struct Value value_from_string(struct String str); 53 | struct Value value_from_array(struct Value_array *arr); 54 | struct Value value_from_keyword(struct String *str); 55 | struct Value value_from_undef(); 56 | 57 | struct Value value_copy_stack(struct Value * b); 58 | struct Value *value_copy_heap(struct Value * b); 59 | void value_copy_to(struct Value * a, struct Value * b); 60 | 61 | size_t length(struct Value a); 62 | 63 | unsigned long value_keyword_hash_code(void *value); 64 | bool value_keyword_equality(void *a, void *b); 65 | 66 | struct String type_to_string(enum Value_type type); 67 | bool value_equals_shallow(struct Value *a, struct Value *b); 68 | void value_negate(struct Value *v); 69 | void value_free(struct Value *v); 70 | void value_free_stack(struct Value v); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/structures/varint.h: -------------------------------------------------------------------------------- 1 | #ifndef VARINT_H 2 | #define VARINT_H 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct varint_t { 9 | size_t sign:1; // 1 = negative 10 | size_t size: sizeof(size_t) * CHAR_BIT - 1; 11 | unsigned char *data; // NOTE: low chars first. 12 | }; 13 | 14 | struct varint_t varint_zero(); 15 | 16 | struct varint_t varint_u_new(const uintmax_t val); 17 | struct varint_t varint_new(intmax_t val); 18 | 19 | void varint_free(struct varint_t *const v); 20 | 21 | 22 | struct varint_t varint_copy(const struct varint_t *const v); 23 | void varint_copy_to(struct varint_t *const to, const struct varint_t *const from); 24 | 25 | bool varint_can_be_uintmax(const struct varint_t *const v); 26 | uintmax_t varint_as_uintmax(const struct varint_t *const v); 27 | 28 | unsigned char varint_char_at_pos(const struct varint_t *const v, const size_t pos); 29 | 30 | void varint_print_dec(const struct varint_t *const v); 31 | struct String varint_to_dec_string(const struct varint_t *const v); 32 | 33 | struct String varint_to_hex_string(const struct varint_t *const v); 34 | void varint_print_hex(const struct varint_t *const v); 35 | 36 | struct String varint_to_base_string(const struct varint_t *const v, const uintmax_t base, const size_t digits_in_group, const char *const digit_sep, char * (* const digit_func)(const uintmax_t)); 37 | 38 | struct varint_t varint_negate(const struct varint_t *const v); 39 | void varint_negate_to(struct varint_t *const v); 40 | 41 | struct varint_t varint_add(const struct varint_t *const a, const struct varint_t *const b); 42 | void varint_add_to(struct varint_t *const a, const struct varint_t *const b); 43 | 44 | struct varint_t varint_sub(const struct varint_t *const a, const struct varint_t *const b) ; 45 | void varint_sub_to(struct varint_t *const a, const struct varint_t *const b); 46 | 47 | struct varint_t varint_mul(const struct varint_t *const a, const struct varint_t *const b); 48 | void varint_mul_to(struct varint_t *const a, const struct varint_t *const b); 49 | 50 | struct varint_t varint_div(const struct varint_t *const v, const struct varint_t *const div_by); 51 | void varint_div_to(struct varint_t *const v, const struct varint_t *const div_by); 52 | 53 | struct varint_t varint_mod(const struct varint_t *const v, const struct varint_t *const mod_by); 54 | void varint_mod_to(struct varint_t *const v, const struct varint_t *const mod_by); 55 | 56 | void varint_div_mod(struct varint_t *const div, struct varint_t *const mod, const struct varint_t *const v_in, const struct varint_t *const div_by_in); 57 | 58 | struct varint_t varint_shift_right_word(const struct varint_t *const v, const size_t num); 59 | void varint_shift_right_word_to(struct varint_t *const v, const size_t num); 60 | 61 | void varint_shift_right_one_bit(struct varint_t *const v); 62 | 63 | struct varint_t varint_shift_left_word(const struct varint_t *const v, const size_t num); 64 | void varint_shift_left_word_to(struct varint_t *const v, const size_t num); 65 | 66 | void varint_mul_small_to(struct varint_t *const a, const unsigned char c); 67 | struct varint_t varint_mul_small(const struct varint_t *const a, const unsigned char c); 68 | 69 | bool varint_equals(const struct varint_t *const a, const struct varint_t *const b); 70 | bool varint_equals_abs(const struct varint_t *const a, const struct varint_t *const b); 71 | 72 | bool varint_equals_zero(const struct varint_t *const v); 73 | bool varint_equals_pm_one(const struct varint_t *const v); 74 | 75 | bool varint_greater_than(const struct varint_t *const a, const struct varint_t *const b); 76 | bool varint_greater_than_abs(const struct varint_t *const a, const struct varint_t *const b); 77 | 78 | int_fast8_t varint_signum(const struct varint_t *const v); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/tokenizer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "constants.h" 5 | #include "config.h" 6 | #include "./structures/token.h" 7 | 8 | struct Tokens * tokenize(struct String file, struct Tokens *content){ 9 | assert(string_is_sane(&file)); 10 | struct Token null_token = { 11 | .data = { 12 | .length = 0, 13 | .body = NULL 14 | } 15 | }; 16 | struct Token cur_token = null_token; 17 | 18 | for (size_t counter = 0; counter < file.length; counter++) { 19 | char c = file.body[counter]; 20 | 21 | if (cur_token.data.length == 0 || !can_be_extended(cur_token.data, c, cur_token.type)) { 22 | if (cur_token.data.length != 0) { 23 | RESIZE(cur_token.data.body, cur_token.data.length + 1); 24 | cur_token.data.body[cur_token.data.length] = 0; 25 | 26 | RESIZE(content->tokens, content->length + 1); 27 | content->tokens[content->length] = cur_token; 28 | content->length++; 29 | } 30 | cur_token = null_token; 31 | cur_token.type = get_token_type(c); 32 | } 33 | RESIZE(cur_token.data.body, cur_token.data.length + 1); 34 | cur_token.data.body[cur_token.data.length] = c; 35 | cur_token.data.length += 1; 36 | 37 | } 38 | if (cur_token.data.length != 0) { 39 | RESIZE(cur_token.data.body, cur_token.data.length + 1); 40 | cur_token.data.body[cur_token.data.length] = 0; 41 | 42 | RESIZE(content->tokens, content->length + 1); 43 | content->tokens[content->length] = cur_token; 44 | content->length++; 45 | } 46 | 47 | cur_token = null_token; 48 | cur_token.type = TOK_EOF; 49 | 50 | RESIZE(content->tokens, content->length + 1); 51 | content->tokens[content->length] = cur_token; 52 | content->length++; 53 | 54 | return content; 55 | } 56 | -------------------------------------------------------------------------------- /src/tokenizer.h: -------------------------------------------------------------------------------- 1 | #ifndef _TOKENIZER_H 2 | #define _TOKENIZER_H 3 | 4 | #include "structures/structures.h" 5 | 6 | struct Tokens * tokenize(struct String file, struct Tokens *content); 7 | 8 | #endif 9 | --------------------------------------------------------------------------------