├── .gitignore ├── .vscode └── settings.json ├── Project.toml ├── README.md └── src ├── Foray.jl ├── evaluator.jl ├── lexer.jl ├── parser.jl └── tests ├── add.fyy ├── func.fyy ├── test.fyy └── variable.fyy /.gitignore: -------------------------------------------------------------------------------- 1 | # Files generated by invoking Julia with --code-coverage 2 | *.jl.cov 3 | *.jl.*.cov 4 | 5 | # Files generated by invoking Julia with --track-allocation 6 | *.jl.mem 7 | 8 | # System-specific files and directories generated by the BinaryProvider and BinDeps packages 9 | # They contain absolute paths specific to the host computer, and so should not be committed 10 | deps/deps.jl 11 | deps/build.log 12 | deps/downloads/ 13 | deps/usr/ 14 | deps/src/ 15 | 16 | # Build artifacts for creating documentation generated by the Documenter package 17 | docs/build/ 18 | docs/site/ 19 | 20 | # File generated by Pkg, the package manager, based on a corresponding Project.toml 21 | # It records a fixed state of all packages used by the project. As such, it should not be 22 | # committed for packages, but should be committed for applications that require a static 23 | # environment. 24 | Manifest.toml -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "julia.environmentPath": "/Users/nobu/WorkSpace/Julia/Foray" 3 | } -------------------------------------------------------------------------------- /Project.toml: -------------------------------------------------------------------------------- 1 | name = "Foray" 2 | uuid = "da8a6c96-b728-420e-b7a6-b0e0708cd18d" 3 | authors = ["bichanna "] 4 | version = "0.0.2" 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

The Foray Programming Language

4 |
5 | 6 | WARNING!! THIS LANGUAGE IS JUST A TOY. 7 | 8 | I made the foray into Julia on the day 2022 started. 9 | 10 | ``` 11 | git clone https://github.com/bichanna/Foray.git 12 | cd Foray/src 13 | ``` 14 | After that you can run your `.fyy` file. 15 | ``` 16 | julia Foray.jl test.fyy 17 | ``` 18 | 19 | ## Syntax 20 | 21 | *Note:* **Currently Foray only supports string.**
22 | *Note:* **Make sure to add an extra line at the end of the file.**
23 | *Note:* **Always place the start function at the top of the file** 24 | 25 | ### Print statement 26 | Just a bit different with 'out' 27 | ``` 28 | start: 29 | printout "Hello World from Foray" 30 | ``` 31 | 32 | ### Variables 33 | Similar to Python 34 | ``` 35 | start: 36 | variable = "Hello World from a variable" 37 | printout variable 38 | ``` 39 | 40 | ### Comment 41 | Yay! Just like Python. 42 | ``` 43 | # printout "This won't be printed out" 44 | ``` 45 | 46 | ### Function(?) 47 | 🤔 Python without def 48 | ``` 49 | something: 50 | printout "Yay" 51 | 52 | start: 53 | run something 54 | printout "This will be printed out after" 55 | ``` 56 | 57 | ### Exit the program 58 | Easy poosy. 59 | ``` 60 | start: 61 | printout "Weee!" 62 | stop 63 | printout "This does not show up." 64 | ``` 65 | -------------------------------------------------------------------------------- /src/Foray.jl: -------------------------------------------------------------------------------- 1 | include("./lexer.jl") 2 | using .Lexer 3 | 4 | include("./parser.jl") 5 | using .Parser 6 | 7 | include("./evaluator.jl") 8 | using .Evaluator 9 | 10 | function printout_error(text::String) 11 | printstyled("Foray: $text\n"; color=:red) 12 | end 13 | 14 | function show_usage() 15 | println("Usage:") 16 | println(" julia Foray.jl .fyy") 17 | end 18 | 19 | if length(ARGS) < 1 20 | show_usage() 21 | exit() 22 | else 23 | global filename = ARGS[1] 24 | end 25 | 26 | try 27 | global extension = filename[end-3] * filename[end-2] * filename[end-1] * filename[end] 28 | catch 29 | printout_error("Foray: Specify a file with .fyy extension") 30 | show_usage() 31 | exit() 32 | end 33 | 34 | if extension != ".fyy" 35 | printout_error("Specify a file with .fyy extension") 36 | show_usage() 37 | exit() 38 | end 39 | 40 | tokens = tokenize(filename) 41 | # println("TOKENS:") 42 | # for t in tokens 43 | # println(""" $(t["id"]): $(t["value"])""") 44 | # end 45 | 46 | AST = build_AST(tokens) 47 | # println("AST:") 48 | # for a in AST 49 | # println(" $a") 50 | # end 51 | 52 | # println("OUTPUTS:") 53 | evaluate(AST, true) -------------------------------------------------------------------------------- /src/evaluator.jl: -------------------------------------------------------------------------------- 1 | module Evaluator 2 | 3 | AST = [] 4 | 5 | function evaluate(node::Union{Vector{Any}, Dict{String, String}}, keep::Bool=false) 6 | if keep 7 | global AST = node 8 | end 9 | 10 | if isa(node, Vector{Any}) 11 | for n in node 12 | for (k, v) in n 13 | execute([k, v]) 14 | end 15 | end 16 | elseif isa(node, Dict{String, String}) 17 | for (k ,v) in node 18 | execute([k, v]) 19 | end 20 | end 21 | end 22 | 23 | function execute(loc::Union{Vector{Any}, Vector{String}}) 24 | if isa(loc[2], Vector{Any}) && loc[1] == "start" 25 | evaluate(loc[2]) 26 | elseif loc[1] == "printout" 27 | printout(loc[2]) 28 | elseif loc[1] == "stop" 29 | exit() 30 | elseif loc[1] == "run" 31 | run_label(loc[2]) 32 | end 33 | end 34 | 35 | function run_label(v::String) 36 | for node in AST 37 | if haskey(node, v) 38 | evaluate(node[v]) 39 | end 40 | end 41 | end 42 | 43 | function printout(value::String) 44 | println(value) 45 | end 46 | 47 | export evaluate 48 | end # module -------------------------------------------------------------------------------- /src/lexer.jl: -------------------------------------------------------------------------------- 1 | module Lexer 2 | 3 | keywords = [ 4 | "printout", 5 | "stop", 6 | "run", 7 | ] 8 | 9 | vars = Dict() 10 | 11 | function tokenize(filename::String) 12 | file = open(filename, "r") 13 | tokens = [] 14 | while !eof(file) 15 | tmp = [] 16 | tid = "" 17 | isvar = false 18 | varkey = "" 19 | for l in readline(file, keep=true) # typeof(l) = Char 20 | if l == '"' && tid == "" 21 | tid = "char" 22 | tmp = [] 23 | elseif l == '"' && tid == "char" 24 | push!(tokens, Dict("id"=>"string", "value"=>join(tmp))) 25 | if isvar == true 26 | vars[varkey] = join(tmp) 27 | end 28 | tid = "" 29 | tmp = [] 30 | elseif haskey(vars, join(tmp)) 31 | push!(tokens, Dict("id"=>"string", "value"=>vars[join(tmp)])) 32 | elseif l == ':' 33 | push!(tokens, Dict("id"=>"label", "value"=>join(tmp))) 34 | tmp = [] 35 | elseif issubset([join(tmp)], keywords) 36 | push!(tokens, Dict("id"=>"keyword", "value"=>join(tmp))) 37 | tmp = [] 38 | elseif l == '=' 39 | push!(tokens, Dict("id"=>"var", "value"=>join(tmp))) 40 | push!(tokens, Dict("id"=>"alloc", "value"=>"eq")) 41 | vars[join(tmp)] = "" 42 | isvar = true 43 | varkey = join(tmp) 44 | tmp = [] 45 | elseif l == '\n' 46 | if length(tmp) > 0 47 | push!(tokens, Dict("id"=>"atom", "value"=>join(tmp))) 48 | tmp = [] 49 | end 50 | elseif (l == ' ' || l == '\t') && tid != "char" 51 | continue 52 | elseif l == '#' && tid != "char" 53 | break 54 | else 55 | push!(tmp, l) 56 | end 57 | end 58 | end 59 | 60 | close(file)# close file 61 | 62 | return tokens 63 | end 64 | 65 | export tokenize 66 | end # module -------------------------------------------------------------------------------- /src/parser.jl: -------------------------------------------------------------------------------- 1 | module Parser 2 | 3 | AST = [] 4 | 5 | function add_node(parent::Union{String, Dict{String, String}}, node::Dict{String, String}) 6 | for a in AST 7 | if typeof(parent) != String 8 | if issubset([parent], a) 9 | push!(a[parent], node) 10 | end 11 | else 12 | if haskey(a, parent) 13 | push!(a[parent], node) 14 | end 15 | end 16 | end 17 | end 18 | 19 | function build_AST(tokens::Vector{Any}) 20 | saved = Dict() 21 | parent = Dict() 22 | collect = false 23 | 24 | for token in tokens 25 | if token["id"] == "label" 26 | t = Dict(token["value"]=>[]) 27 | if parent != t 28 | parent = token["value"] 29 | push!(AST, t) 30 | end 31 | elseif token["id"] == "keyword" || token["id"] == "var" 32 | if token["value"] == "stop" 33 | t = Dict(token["value"]=>"") 34 | add_node(parent, t) 35 | else 36 | if collect == false 37 | saved = token 38 | collect = true 39 | else 40 | t = Dict(saved["value"]=>token["value"]) 41 | add_node(parent, t) 42 | collect = false 43 | end 44 | end 45 | elseif token["id"] == "string" || token["id"] == "atom" 46 | if collect == false 47 | saved = token 48 | collect = true 49 | else 50 | t = Dict(saved["value"]=>token["value"]) 51 | add_node(parent, t) 52 | collect = false 53 | end 54 | end 55 | end 56 | return AST 57 | end 58 | 59 | export build_AST 60 | end # module -------------------------------------------------------------------------------- /src/tests/add.fyy: -------------------------------------------------------------------------------- 1 | 1 + 1 -------------------------------------------------------------------------------- /src/tests/func.fyy: -------------------------------------------------------------------------------- 1 | start: 2 | run func 3 | 4 | func: 5 | printout "Hello" -------------------------------------------------------------------------------- /src/tests/test.fyy: -------------------------------------------------------------------------------- 1 | something: 2 | printout "Yay" 3 | 4 | start: 5 | run something 6 | printout "This will be printed out after something func" 7 | run another 8 | 9 | 10 | another: 11 | printout "Hello World from another function" 12 | -------------------------------------------------------------------------------- /src/tests/variable.fyy: -------------------------------------------------------------------------------- 1 | start: 2 | str = "This is a variable" 3 | printout str 4 | --------------------------------------------------------------------------------