-
Notifications
You must be signed in to change notification settings - Fork 41
/
cli.ngs
139 lines (117 loc) · 3.38 KB
/
cli.ngs
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
ns {
# WIP, don't use!
F help() {
echo(2, Lines([
"Help - Running NGS"
""
"Option 1: run an ngs script"
" Run ngs with a file name as an argument:"
" ngs MY_SCRIPT.ngs"
""
"Option 2: use ngs as an interpreter"
" Start your ngs script with the following line (without spaces in the beginning):"
" #!/usr/bin/env ngs"
" ... and remember to 'chmod +x' the script file"
""
"Option 3: use one of the following switches:"
" ngs -e EXPR evaluate EXPR"
" ngs -p EXPR evaluate EXPR and print the result"
" ngs -pl EXPR evaluate EXPR and print each element of result on it's own line"
" ngs -pj EXPR evaluate EXPR, convert the result to JSON and print it"
" ngs -pjl EXPR evaluate EXPR, convert each element of the result to"
" JSON and print one element per line"
" ngs -pt EXPR evaluate EXPR, print the result as a table"
" ngs -pi EXPR evaluate EXPR and print inspection (detailed information) of the result"
" (in EXPR, _ variable contains (on-demand) read and parsed stdin)"
""
"For more information, see NGS site at https://ngs-lang.org/"
]))
}
F make_prompt() {
cli_prompt.map(F(k, v) v()).join(' ')
}
# XXX: Ugly hack to prevent direct output to stdout.
# It's okayish because since we are in CLI mode
# none of the commands can be "top level".
# A real fix would be somehow let compiler know it's not a top-level.
# XXX: Do this after rc files are executed !
F '$()'(c:Command) {
c.options .= without('top_level')
guard false
}
F run_cli_rc_files() {
rc_files = ['/etc/ngs/cli.rc.ngs']
if 'HOME' in ENV {
rc_files.push("${ENV['HOME']}/.ngs/cli.rc.ngs")
}
rc_files.filter(Path).each(F(f) {
debug("[CLI] Loading RC file $f")
require(f)
})
}
F main() {
if not(ENV.has('NGS_DEV_CLI')) {
F e(s:Str) {
echo(2, s)
}
e("You have started NGS with no command line arguments.")
e("In future this will invoke the CLI (shell). Currently the CLI is not implemented yet.")
e("")
help()
exit(1)
}
debug('Starting NGS CLI')
echo('*** NGS CLI is under construction ***')
echo('| After successful command, R variable contains the result')
echo('| After unsuccessful command, E variable contains the exception')
not(0.isatty() and 1.isatty()) throws Error("CLI only runs when attached to a TTY")
screen_renderer = Screen::Renderer()
run_cli_rc_files()
rl = FFI(cli_readline_lib, 'readline', c_ffi_type_string, [c_ffi_type_string])
while true {
line = rl(make_prompt())
if line is Null {
echo('')
echo('BYE')
break
}
line == "" continues
had_error = false
try {
program_bytecode = compile(line, '<cli-entered-line>')
program_func = load(program_bytecode, 'cli_entered_line')
result = program_func()
} catch(e:Exception) {
global E = e
echo("ERROR: $e")
had_error = true
}
had_error continues
if(result is Process) {
result.wait()
}
global R = result
s = Str(result)
if('\n' in s) {
echo("RESULT:")
s.split('\n').each(F(line) {
echo(" $line")
})
} else {
echo("RESULT: $s")
}
}
}
# --- Start ---
cli_readline_lib = 'libreadline.so.6'
# TODO: make it object, not a string
cli_prompt = {
'ngs': F() 'NGS'
'dir': F() {
# TODO: replace HOME dir with ~
p = $(pwd).Str()
p[0..len(p)-1]
}
'gt': F() '> '
}
}