11package evaluator
22
33import (
4- "bufio"
5- "os"
64 "path/filepath"
75
86 "github.com/skx/monkey/object"
97)
108
11- //
12- // Mapping of file-IDs to file-handles
13- //
14- var fileHandles = make (map [uintptr ]* os.File )
15- var fileReaders = make (map [uintptr ]* bufio.Reader )
16- var fileWriters = make (map [uintptr ]* bufio.Writer )
17-
18- //
19- // Horrid hack - setup STDIN/STDOUT/STDERR
20- //
21- func setupHandles () {
22- if fileHandles [0 ] != nil {
23- return
24- }
25- fileHandles [0 ] = os .Stdin
26- fileHandles [1 ] = os .Stdout
27- fileHandles [2 ] = os .Stderr
28-
29- fileReaders [0 ] = bufio .NewReader (os .Stdin )
30- fileReaders [1 ] = bufio .NewReader (os .Stdout )
31- fileReaders [2 ] = bufio .NewReader (os .Stderr )
32-
33- fileWriters [0 ] = bufio .NewWriter (os .Stdin )
34- fileWriters [1 ] = bufio .NewWriter (os .Stdout )
35- fileWriters [2 ] = bufio .NewWriter (os .Stderr )
36- }
37-
389// array = directory.glob( "/etc/*.conf" )
3910func dirGlob (args ... object.Object ) object.Object {
4011 if len (args ) != 1 {
@@ -57,164 +28,9 @@ func dirGlob(args ...object.Object) object.Object {
5728 return & object.Array {Elements : result }
5829}
5930
60- // handle = file.open(path)
61- func fileOpen (args ... object.Object ) object.Object {
62- setupHandles ()
63- if len (args ) != 1 && len (args ) != 2 {
64- return newError ("wrong number of arguments. got=%d, want=1|2" ,
65- len (args ))
66- }
67-
68- path := args [0 ].(* object.String ).Value
69-
70- md := os .O_RDONLY
71- if len (args ) == 2 {
72- mode := args [1 ].(* object.String ).Value
73- if mode == "w" {
74- md = os .O_WRONLY
75- }
76-
77- }
78- file , err := os .OpenFile (path , os .O_CREATE | md , 0644 )
79- if err != nil {
80- return & object.Integer {Value : - 1 }
81- }
82-
83- // convert handle to integer to return it
84- fileHandles [file .Fd ()] = file
85-
86- // but also store a reader / writer as appropriate
87- if md == os .O_RDONLY {
88- fileReaders [file .Fd ()] = bufio .NewReader (file )
89- } else {
90- fileWriters [file .Fd ()] = bufio .NewWriter (file )
91- }
92-
93- return & object.Integer {Value : int64 (file .Fd ())}
94- }
95-
96- // file.close(handle)
97- func fileClose (args ... object.Object ) object.Object {
98- setupHandles ()
99- if len (args ) != 1 {
100- return newError ("wrong number of arguments. got=%d, want=1" ,
101- len (args ))
102- }
103-
104- handle := args [0 ].(* object.Integer ).Value
105-
106- // If the file was opened for writing then we must flush
107- // it before we close the handle - otherwise our written
108- // data might be lost.
109- if fileWriters [uintptr (handle )] != nil {
110- fileWriters [uintptr (handle )].Flush ()
111- }
112- fileHandles [uintptr (handle )].Close ()
113- delete (fileHandles , uintptr (handle ))
114- delete (fileReaders , uintptr (handle ))
115- delete (fileWriters , uintptr (handle ))
116- return NULL
117- }
118-
119- // [] = file.lines("path")
120- func fileLines (args ... object.Object ) object.Object {
121- setupHandles ()
122- if len (args ) != 1 {
123- return newError ("wrong number of arguments. got=%d, want=1" ,
124- len (args ))
125- }
126-
127- path := args [0 ].(* object.String ).Value
128- file , err := os .Open (path )
129- if err != nil {
130- return NULL
131- }
132- defer file .Close ()
133-
134- var lines []string
135- scanner := bufio .NewScanner (file )
136- for scanner .Scan () {
137- lines = append (lines , scanner .Text ())
138- }
139-
140- // make results
141- l := len (lines )
142- result := make ([]object.Object , l , l )
143- for i , txt := range lines {
144- result [i ] = & object.String {Value : txt }
145- }
146- return & object.Array {Elements : result }
147- }
148-
149- // str = read(handle)
150- func readInput (args ... object.Object ) object.Object {
151- setupHandles ()
152- if len (args ) != 1 {
153- return newError ("wrong number of arguments. got=%d, want=1" ,
154- len (args ))
155- }
156-
157- id := args [0 ].(* object.Integer ).Value
158- reader := fileReaders [uintptr (id )]
159- if reader == nil {
160- return newError ("Reading from an unopened file-handle." )
161- }
162-
163- line , err := reader .ReadString ('\n' )
164- if err == nil {
165- return & object.String {Value : line }
166- }
167- return & object.String {Value : "" }
168- }
169-
170- // write(handle, text)
171- func writeOutput (args ... object.Object ) object.Object {
172- setupHandles ()
173- if len (args ) != 2 {
174- return newError ("wrong number of arguments. got=%d, want=2" ,
175- len (args ))
176- }
177-
178- id := args [0 ].(* object.Integer ).Value
179- txt := args [1 ].(* object.String ).Value
180-
181- writer := fileWriters [uintptr (id )]
182- if writer == nil {
183- return newError ("Writing to an unopened file-handle." )
184- }
185-
186- _ , err := writer .Write ([]byte (txt ))
187- if err == nil {
188- writer .Flush ()
189- return & object.Boolean {Value : true }
190- }
191-
192- return & object.Boolean {Value : false }
193- }
194-
19531func init () {
19632 RegisterBuiltin ("directory.glob" ,
19733 func (env * object.Environment , args ... object.Object ) object.Object {
19834 return (dirGlob (args ... ))
19935 })
200- RegisterBuiltin ("read" ,
201- func (env * object.Environment , args ... object.Object ) object.Object {
202- return (readInput (args ... ))
203- })
204- RegisterBuiltin ("write" ,
205- func (env * object.Environment , args ... object.Object ) object.Object {
206- return (writeOutput (args ... ))
207- })
208- RegisterBuiltin ("file.open" ,
209- func (env * object.Environment , args ... object.Object ) object.Object {
210- return (fileOpen (args ... ))
211- })
212- RegisterBuiltin ("file.close" ,
213- func (env * object.Environment , args ... object.Object ) object.Object {
214- return (fileClose (args ... ))
215- })
216- RegisterBuiltin ("file.lines" ,
217- func (env * object.Environment , args ... object.Object ) object.Object {
218- return (fileLines (args ... ))
219- })
22036}
0 commit comments