code / nomsu

Lines6.6K Lua5.1K PEG1.3K make117
2 others 83
Markdown60 Bourne Again Shell23
(230 lines)
1 #!/usr/bin/env moon
2 -- This file contains the command-line Nomsu runner.
3 export NOMSU_VERSION
4 NOMSU_VERSION = {7, 0, 1}
6 clibtype = package.cpath\match("?%.(so)") or package.cpath\match("?%.(dll)")
8 if NOMSU_PREFIX
9 package.path = "#{NOMSU_PREFIX}/share/nomsu/#{table.concat NOMSU_VERSION, "."}/?.lua;"..package.path
10 package.cpath = "#{NOMSU_PREFIX}/lib/nomsu/#{table.concat NOMSU_VERSION, "."}/?.#{clibtype};"..package.cpath
12 export COLOR_ENABLED
13 COLOR_ENABLED = true
14 if clibtype == "dll"
15 -- Enable colors:
16 ok,enable_colors = pcall(require, 'wincolors')
17 COLOR_ENABLED = false
18 if ok
19 ok,_ = pcall(enable_colors)
20 if ok
21 COLOR_ENABLED = false
22 -- Special hack to enable utf8 for windows console applications:
23 pcall(os.execute,"chcp 65001>nul")
25 {:List, :Dict} = require 'containers'
26 NOMSU_VERSION = List(NOMSU_VERSION)
27 Text = require 'text'
28 require 'builtin_metatables'
29 EXIT_FAILURE = 1
30 EXIT_SUCCESS = 0
32 usage = [=[
33 Nomsu Usage: nomsu [-V version] [--help | -h] [--version] [-O optimization level] [-v] [-c] [-s] [-d debugger] [--no-core] [(file | -t tool | -e "nomsu code..." | files... -- ) [nomsu args...]]
35 OPTIONS
36 -t <tool> Run a tool.
37 -e Execute the specified string.
38 -O <level> Run the compiler with the given optimization level (>0: use precompiled .lua versions of Nomsu files, when available).
39 -v Verbose: print compiled lua code.
40 -c Compile the input files into a .lua files.
41 -s Check the input files for syntax errors.
42 -d <debugger> Attempt to use the specified debugger to wrap the main body of execution.
43 -h/--help Print this message.
44 --version Print the version number and exit.
45 --no-core Skip loading the Nomsu core by default.
46 -V specify which Nomsu version is desired.
47 <file> The Nomsu file to run (can be "-" to use stdin).
48 ]=]
50 ok, _ = pcall ->
51 export lpeg, re
52 lpeg = require 'lpeg'
53 re = require 're'
54 if not ok
55 print("Error: unable to find the 'lpeg' Lua module. Please install LPEG either from http://www.inf.puc-rio.br/~roberto/lpeg/re.html or, if you use luarocks: `luarocks install lpeg`")
56 os.exit(EXIT_FAILURE)
57 Files = require "files"
58 {:NomsuCode, :LuaCode, :Source} = require "code_obj"
60 sep = "\3"
61 parser = re.compile([[
62 args <- {| (flag %sep)*
63 {:files: {|
64 ( ("-m" %sep)? (file %sep)+ "--" %sep
65 / file %sep
66 / {~ '' %sep? -> 'nomsu://tools/repl.nom' ~}) |} :}
67 {:nomsu_args: {| (nomsu_flag %sep)* {:extras: {| ({[^%sep]+} %sep)* |} :} |} :}
68 |} ({.+}?)
70 file <-
71 ( "-e" %sep ({[^%sep]+} -> spoof)
72 / "-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~}
73 / !"--" {[^%sep]+})
75 flag <- longflag / shortflag / "-" shortboolflag+
76 longflag <-
77 {:help: "--help" %true :}
78 / {:version: "--version" %true :}
79 / {:no_core: "--no-core" %true :}
80 shortflag <-
81 {:optimization: "-O" %sep? %number :}
82 / {:debugger: ("-d" %sep? {[^%sep]+}) :}
83 / {:requested_version: "-V" %sep? {([0-9.])+} :}
84 shortboolflag <-
85 {:check_syntax: "s" %true:}
86 / {:compile: "c" %true:}
87 / {:verbose: "v" %true :}
88 / {:help: "h" %true :}
90 nomsu_flag <- nomsu_longflag / "-" nomsu_shortboolflag+
91 nomsu_shortboolflag <- {| {:key: [a-zA-Z] :} {:value: %true :} |}
92 nomsu_longflag <- '--' {| {:key: [^%sep=]+ :} {:value: ('=' {[^%sep]+}) / %true :} |}
93 ]], {
94 true:lpeg.Cc(true), number:lpeg.R("09")^1/tonumber, sep:lpeg.P(sep),
95 spoof: Files.spoof
96 })
97 arg_string = table.concat(arg, sep)..sep
98 args, err = parser\match(arg_string)
99 if not args or err
100 if err
101 print("Didn't understand: #{err}")
102 print usage
103 os.exit(EXIT_FAILURE)
104 if args.help
105 print "Nomsu - A dynamically typed programming language with natural syntax and strong metaprogramming abilities."
106 print "https://nomsu.org\n"
107 print usage
108 os.exit(EXIT_SUCCESS)
109 if args.version
110 print(NOMSU_VERSION\joined_with("."))
111 os.exit(EXIT_SUCCESS)
112 nomsu_args = Dict{}
113 for argpair in *args.nomsu_args
114 nomsu_args[argpair.key] = argpair.value
115 nomsu_args.extras = List(args.nomsu_args.extras or {})
116 optimization = tonumber(args.optimization or 1)
118 nomsupath = {}
119 suffixes = if optimization > 0
120 {"?.lua", "?/init.lua", "?.nom", "?/init.nom"}
121 else {"?.nom", "?/init.nom"}
122 add_path = (p)->
123 for s in *suffixes do table.insert(nomsupath, p.."/"..s)
124 if NOMSU_PREFIX
125 add_path "#{NOMSU_PREFIX}/share/nomsu/#{NOMSU_VERSION\joined_with(".")}/lib"
126 else
127 add_path "./lib"
128 NOMSU_PACKAGEPATH or= "/opt/nomsu"
129 add_path NOMSU_PACKAGEPATH
130 add_path "."
131 package.nomsupath = table.concat(nomsupath, ";")
132 package.nomsuloaded = Dict{}
134 nomsu_environment = require('nomsu_environment')
135 nomsu_environment.NOMSU_VERSION = NOMSU_VERSION
136 nomsu_environment.COMMAND_LINE_ARGS = nomsu_args
137 nomsu_environment.OPTIMIZATION = optimization
138 nomsu_environment.NOMSU_PACKAGEPATH = NOMSU_PACKAGEPATH
139 nomsu_environment.NOMSU_PREFIX = NOMSU_PREFIX
140 nomsu_environment.COLOR_ENABLED = COLOR_ENABLED
142 run = ->
143 unless args.no_core
144 nomsu_environment\export("core")
146 input_files = {}
147 if args.files and #args.files > 0
148 for f in *args.files
149 if nomsu_name = f\match("^nomsu://(.*)%.nom")
150 path, err = package.searchpath(nomsu_name, package.nomsupath, "/")
151 if not path then error(err)
152 table.insert input_files, path
153 else
154 table.insert input_files, f
156 for filename in *input_files
157 if args.check_syntax
158 -- Check syntax
159 code = Files.read(filename)
160 source = Source(filename, 1, #code)
161 nomsu_environment._1_parsed(NomsuCode\from(source, code))
162 print("Parse succeeded: #{filename}")
163 elseif args.compile
164 code = Files.read(filename)
165 if not code
166 error("Could not find file '#{filename}'")
167 -- Compile .nom files into .lua
168 if filename\match("%.lua$")
169 error("Cannot compile a lua file (expected a nomsu file as input)")
170 output = if filename == 'stdin' then io.output()
171 else io.open(filename\gsub("%.nom$", ".lua"), "w")
172 source = Source(filename, 1, #code)
173 code = NomsuCode\from(source, code)
174 env = nomsu_environment.new_environment!
175 env.MODULE_NAME = filename
176 tree = env._1_parsed(code)
177 if tree.shebang
178 output\write tree.shebang
179 tree = {tree} unless tree.type == 'FileChunks'
180 for chunk_no, chunk in ipairs tree
181 lua = env\compile(chunk)
182 lua\declare_locals!
183 lua\prepend((chunk_no > 1) and '\n' or '', "-- File #{filename} chunk ##{chunk_no}\n")
184 if args.verbose then print(lua\text!)
185 env\run(chunk)
186 output\write(lua\text!, "\n")
187 print ("Compiled %-25s -> %s")\format(filename, filename\gsub("%.nom$", ".lua"))
188 output\close!
189 elseif args.verbose
190 env = nomsu_environment.new_environment!
191 env.MODULE_NAME = filename
192 env.WAS_RUN_DIRECTLY = true
193 code = Files.read(filename)
194 source = Source(filename, 1, #code)
195 if filename\match("%.lua$")
196 code = LuaCode\from(Source(filename, 1, #code), code)
197 print(code\text!)
198 env\run(code)
199 else
200 code = NomsuCode\from(source, code)
201 tree = env._1_parsed(code)
202 tree = {tree} unless tree.type == 'FileChunks'
203 for chunk_no, chunk in ipairs tree
204 lua = env\compile(chunk)
205 lua\declare_locals!
206 lua\prepend((chunk_no > 1) and '\n' or '', "-- File #{filename} chunk ##{chunk_no}\n")
207 print(lua\text!)
208 env\run(lua)
209 else
210 -- Just run the file
211 f = Files.read(filename)
212 if not f
213 if filename\match "^-"
214 print "Not a valid flag: "..filename.."\n"
215 print usage
216 else
217 print "File not found: "..filename
218 os.exit EXIT_FAILURE
219 if filename\match("%.lua$")
220 f = LuaCode\from(Source(filename, 1, #f), f)
221 env = nomsu_environment.new_environment!
222 env.MODULE_NAME = filename
223 env.WAS_RUN_DIRECTLY = true
224 env\run(f)
226 debugger = if args.debugger == "nil" then {}
227 else require(args.debugger or 'error_handling')
228 guard = if type(debugger) == 'function' then debugger
229 else debugger.guard or debugger.call or debugger.wrap or debugger.run or ((fn)->fn())
230 guard(run)