#!/usr/bin/env moon – This file contains the command-line Nomsu runner. export NOMSUVERSION NOMSUVERSION = {7, 0, 1}
clibtype = package.cpath\match(“?%.(so)”) or package.cpath\match(“?%.(dll)”)
if NOMSUPREFIX package.path = “#{NOMSUPREFIX}/share/nomsu/#{table.concat NOMSUVERSION, “.”}/?.lua;”..package.path package.cpath = “#{NOMSUPREFIX}/lib/nomsu/#{table.concat NOMSU_VERSION, “.”}/?.#{clibtype};”..package.cpath
export COLORENABLED COLORENABLED = true if clibtype == “dll” – Enable colors: ok,enablecolors = pcall(require, ‘wincolors’) COLORENABLED = false if ok ok,_ = pcall(enablecolors) if ok COLORENABLED = false – Special hack to enable utf8 for windows console applications: pcall(os.execute,"chcp 65001>nul”)
{:List, :Dict} = require ‘containers’ NOMSUVERSION = List(NOMSUVERSION) Text = require ‘text’ require ‘builtinmetatables’ EXITFAILURE = 1 EXIT_SUCCESS = 0
usage = [=[ 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…]]
OPTIONS
-t
ok, _ = pcall ->
export lpeg, re
lpeg = require ‘lpeg’
re = require ‘re’
if not ok
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”)
os.exit(EXITFAILURE)
Files = require “files”
{:NomsuCode, :LuaCode, :Source} = require “codeobj”
sep = “\3” parser = re.compile([[ args <- {| (flag %sep)* {:files: {| ( (“-m” %sep)? (file %sep)+ “–” %sep / file %sep / {~ ‘‘ %sep? -> ‘nomsu://tools/repl.nom’ ~}) |} :} {:nomsuargs: {| (nomsuflag %sep)* {:extras: {| ({[^%sep]+} %sep)* |} :} |} :} |} ({.+}?)
file <-
( "-e" %sep ({[^%sep]+} -> spoof)
/ "-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~}
/ !"--" {[^%sep]+})
flag <- longflag / shortflag / "-" shortboolflag+
longflag <-
{:help: "--help" %true :}
/ {:version: "--version" %true :}
/ {:no_core: "--no-core" %true :}
shortflag <-
{:optimization: "-O" %sep? %number :}
/ {:debugger: ("-d" %sep? {[^%sep]+}) :}
/ {:requested_version: "-V" %sep? {([0-9.])+} :}
shortboolflag <-
{:check_syntax: "s" %true:}
/ {:compile: "c" %true:}
/ {:verbose: "v" %true :}
/ {:help: "h" %true :}
nomsu_flag <- nomsu_longflag / "-" nomsu_shortboolflag+
nomsu_shortboolflag <- {| {:key: [a-zA-Z] :} {:value: %true :} |}
nomsu_longflag <- '--' {| {:key: [^%sep=]+ :} {:value: ('=' {[^%sep]+}) / %true :} |}
]], { true:lpeg.Cc(true), number:lpeg.R(“09”)^1/tonumber, sep:lpeg.P(sep), spoof: Files.spoof }) argstring = table.concat(arg, sep)..sep args, err = parser\match(argstring) if not args or err if err print(“Didn’t understand: #{err}”) print usage os.exit(EXITFAILURE) if args.help print “Nomsu - A dynamically typed programming language with natural syntax and strong metaprogramming abilities.” print “https://nomsu.org\n” print usage os.exit(EXITSUCCESS) if args.version print(NOMSUVERSION\joinedwith(“.”)) os.exit(EXITSUCCESS) nomsuargs = Dict{} for argpair in *args.nomsuargs nomsuargs[argpair.key] = argpair.value nomsuargs.extras = List(args.nomsuargs.extras or {}) optimization = tonumber(args.optimization or 1)
nomsupath = {} suffixes = if optimization > 0 {”?.lua”, “?/init.lua”, “?.nom”, “?/init.nom”} else {”?.nom”, “?/init.nom”} addpath = (p)-> for s in *suffixes do table.insert(nomsupath, p..”/”..s) if NOMSUPREFIX addpath “#{NOMSUPREFIX}/share/nomsu/#{NOMSUVERSION\joinedwith(“.”)}/lib” else addpath “./lib” NOMSUPACKAGEPATH or= “/opt/nomsu” addpath NOMSUPACKAGEPATH add_path “.” package.nomsupath = table.concat(nomsupath, “;”) package.nomsuloaded = Dict{}
nomsuenvironment = require(‘nomsuenvironment’) nomsuenvironment.NOMSUVERSION = NOMSUVERSION nomsuenvironment.COMMANDLINEARGS = nomsuargs nomsuenvironment.OPTIMIZATION = optimization nomsuenvironment.NOMSUPACKAGEPATH = NOMSUPACKAGEPATH nomsuenvironment.NOMSUPREFIX = NOMSUPREFIX nomsuenvironment.COLORENABLED = COLOR_ENABLED
run = -> unless args.nocore nomsuenvironment\export(“core”)
input_files = {}
if args.files and #args.files > 0
for f in *args.files
if nomsu_name = f\match("^nomsu://(.*)%.nom")
path, err = package.searchpath(nomsu_name, package.nomsupath, "/")
if not path then error(err)
table.insert input_files, path
else
table.insert input_files, f
for filename in *input_files
if args.check_syntax
-- Check syntax
code = Files.read(filename)
source = Source(filename, 1, #code)
nomsu_environment._1_parsed(NomsuCode\from(source, code))
print("Parse succeeded: #{filename}")
elseif args.compile
code = Files.read(filename)
if not code
error("Could not find file '#{filename}'")
-- Compile .nom files into .lua
if filename\match("%.lua$")
error("Cannot compile a lua file (expected a nomsu file as input)")
output = if filename == 'stdin' then io.output()
else io.open(filename\gsub("%.nom$", ".lua"), "w")
source = Source(filename, 1, #code)
code = NomsuCode\from(source, code)
env = nomsu_environment.new_environment!
env.MODULE_NAME = filename
tree = env._1_parsed(code)
if tree.shebang
output\write tree.shebang
tree = {tree} unless tree.type == 'FileChunks'
for chunk_no, chunk in ipairs tree
lua = env\compile(chunk)
lua\declare_locals!
lua\prepend((chunk_no > 1) and '\n' or '', "-- File #{filename} chunk ##{chunk_no}\n")
if args.verbose then print(lua\text!)
env\run(chunk)
output\write(lua\text!, "\n")
print ("Compiled %-25s -> %s")\format(filename, filename\gsub("%.nom$", ".lua"))
output\close!
elseif args.verbose
env = nomsu_environment.new_environment!
env.MODULE_NAME = filename
env.WAS_RUN_DIRECTLY = true
code = Files.read(filename)
source = Source(filename, 1, #code)
if filename\match("%.lua$")
code = LuaCode\from(Source(filename, 1, #code), code)
print(code\text!)
env\run(code)
else
code = NomsuCode\from(source, code)
tree = env._1_parsed(code)
tree = {tree} unless tree.type == 'FileChunks'
for chunk_no, chunk in ipairs tree
lua = env\compile(chunk)
lua\declare_locals!
lua\prepend((chunk_no > 1) and '\n' or '', "-- File #{filename} chunk ##{chunk_no}\n")
print(lua\text!)
env\run(lua)
else
-- Just run the file
f = Files.read(filename)
if not f
if filename\match "^-"
print "Not a valid flag: "..filename.."\n"
print usage
else
print "File not found: "..filename
os.exit EXIT_FAILURE
if filename\match("%.lua$")
f = LuaCode\from(Source(filename, 1, #f), f)
env = nomsu_environment.new_environment!
env.MODULE_NAME = filename
env.WAS_RUN_DIRECTLY = true
env\run(f)
debugger = if args.debugger == “nil” then {} else require(args.debugger or ‘error_handling’) guard = if type(debugger) == ‘function’ then debugger else debugger.guard or debugger.call or debugger.wrap or debugger.run or ((fn)->fn()) guard(run)
