1818# -----------------------------------------------------------------------
1919
2020module MoonScript
21- class Workspace
22- getter result: TypeChecker | Error = Error .new(:uninitialized_workspace )
23-
24- @cache : Hash (String , Ast | Error ) = {} of String => Ast | Error
21+ class Workspace
22+ getter result : TypeChecker | Error = Error .new(:unitialized_workspace )
23+
24+ @cache : Hash (String , Ast | Error ) = {} of String => Ast | Error
25+ @listener : Proc (TypeChecker | Error , Nil ) | Nil
26+
27+ def initialize (
28+ * ,
29+ @listener : Proc (TypeChecker | Error , Nil ) | Nil ,
30+ @include_tests : Bool ,
31+ dot_env : String ,
32+ @format : Bool ,
33+ @check : Check ,
34+ @path : String ,
35+ )
36+ @dot_env =
37+ File .basename(dot_env)
38+
39+ (@watcher = Watcher .new(&- > update(Array (String ), Symbol )))
40+ .tap { reset }
41+ .watch
42+ end
2543
26- @listener : Proc (TypeChecker | Error , Nil ) | Nil
44+ def update (contents : String , path : String ) : Nil
45+ @cache [path] = Parser .parse?(contents, path)
46+ end
2747
28- def initialize (* , @listener : Proc (TypeChecker | Error , Nil ) | Nil , @include_tests : Bool , dot_env: String , @format : Bool , @check : Check , @path : String )
29- @dot_env = File .basename(dot_env)
48+ def delete (path : String ) : Nil
49+ @cache .delete(path)
50+ end
3051
31- (@watcher = Watcher .new(&- > update(Array (String ), Symbol )))
32- .tap { reset }
33- .watch
34- end
52+ def artifacts : TypeChecker ::Artifacts | Error
53+ map_error(result, & .artifacts)
54+ end
3555
36- def update ( contents: String , path: String ) : Nil
37- @cache [path] = Parser .parse?(contents, path)
38- end
56+ def ast ( path : String ) : Ast | Error | Nil
57+ @cache [path]?
58+ end
3959
40- def delete ( path: String ) : Nil
41- @cache .delete(path )
42- end
60+ def ast : Ast | Error
61+ map_error(artifacts, & .ast )
62+ end
4363
44- def artifacts : TypeChecker ::Artifacts | Error
45- map_error(result, & .artifacts)
64+ def unchecked_ast
65+ @cache
66+ .values
67+ .select(Ast )
68+ .reduce(Ast .new) { |memo , item | memo.merge item }
69+ .tap do |item |
70+ unless item.type_definitions.index(& .name.== (" Maybe" ))
71+ item.merge(Core .ast)
72+ end
4673 end
74+ .normalize
75+ end
4776
48- def ast (path: String ) : Ast | Error | Nil
49- @cache [path]?
50- end
77+ def nodes_at_cursor (
78+ * ,
79+ column : Int64 ,
80+ path : String ,
81+ line : Int64 ,
82+ ) : Array (Ast ::Node ) | Error
83+ map_error(ast, & .nodes_at_cursor(
84+ line: line, column: column, path: path))
85+ end
5186
52- def ast: Ast | Error
53- map_error(artifacts , & .ast )
54- end
87+ def nodes_at_path (path : String )
88+ map_error(ast , & .nodes_at_path(path) )
89+ end
5590
56- def nodes_at_path (path: String )
57- map_error(ast, & .nodes_at_path(path))
58- end
91+ def formatter_config
92+ MoonJson .parse?(@path , search: true ).try(& .formatter) ||
93+ Formatter ::Config .new
94+ end
5995
60- def formatter_config
61- MoonJson .parse?( @path , search: true ).try( & .formatter) || Formatter :: Config .new
62- end
96+ def format (node : Ast :: Node | Nil ) : String | Nil
97+ Formatter .new(formatter_config).format!(node)
98+ end
6399
64- def format (node: Ast ::Node | Nil ) : String | Nil
65- Formatter .new(formatter_config).format!(node)
66- end
100+ def format (path : String ) : String | Error | Nil
101+ case item = ast(path)
102+ in Ast
103+ Formatter .new(formatter_config).format(item)
104+ in Error , Nil
105+ item
106+ end
107+ end
67108
68- def format (path: String ) : String | Error | Nil
69- case item = ast(path)
70- in Ast
71- Formatter .new(formatter_config).format(item)
72- in Error , Nil
73- item
74- end
75- end
109+ def reset
110+ @cache .clear
111+ @watcher .patterns =
112+ SourceFiles .everything(
113+ MoonJson .parse(@path , search: true ),
114+ include_tests: @include_tests ,
115+ dot_env: @dot_env )
116+ rescue error : Error
117+ set(error)
118+ end
76119
77- def reset
78- @cache .clear
79- @watcher .patterns = SourceFiles .everything(MoonJson .parse(@path , search: true ), include_tests: @include_tests , dot_env: @dot_env )
80- rescue error: Error
81- set(error)
120+ def check
121+ Logger .log " Type Checking" do
122+ if error = @cache .values.select(Error ).first?
123+ error
124+ else
125+ TypeChecker .new(
126+ check_everything: @check .unreachable?,
127+ check_env: @check .environment?,
128+ ast: unchecked_ast
129+ ).tap(& .check)
82130 end
131+ end
132+ rescue error : Error
133+ error
134+ end
83135
84- def check
85- Logger .log " Type checking" do
86- if error = @cache .values.select(Error ).first?
87- error
88- else
89- TypeChecker .new(check_everything: @check .unreachable?, check_env: @check .environment, ast: unchecked_ast).tap(& check)
136+ def update (files : Array (String ), reason : Symbol )
137+ actions = [] of Symbol
138+
139+ Logger .log " Parsing files" do
140+ files.each do |file |
141+ if File .extname(file) == " .moon"
142+ if File .exists?(file)
143+ contents = File .read(file)
144+ update(contents, file)
145+
146+ if @format
147+ case ast = ast(file)
148+ when Ast
149+ formatted =
150+ Formatter .new(formatter_config).format(ast) + " \n "
151+
152+ if formatted != contents
153+ File .write(file, formatted)
154+ end
90155 end
91- rescue error: Error
92- error
156+ end
157+ else
158+ delete(file)
93159 end
94- end
95160
96- def update (files: Array (String ), reason: Symbol )
97- actions = [] of Symbol
98-
99- Logger .log " Parsing files" do
100- files.each do |file |
101- if File .extname(file) == " .moon"
102- if File .exists?(file)
103- contents = File .read(file)
104- update(contents, file)
105-
106- if @format
107- case ast = ast(file)
108- when Ast formatted = Formatter .new(formatter_config).format(ast) + " \n "
109-
110- end
161+ actions << :compile
162+ else
163+ case File .basename(file)
164+ when @dot_env
165+ Env .init(file)
166+ end
111167
112- private def set (value : TypeChecker | Error ) : Nil
113- @result = value
114- @listener .try(& .call(value))
168+ actions << :reset
169+ end
115170 end
171+ end
116172
117- private def map_error (item : T | Error , & : T - > R ) : R | Error forall T , R
118- case item
119- in Error
120- item
121- in T
122- yield item
123- end
124- end
125-
173+ if actions.includes?(:reset ) && reason == :modified
174+ reset
175+ elsif actions.includes?(:compile )
176+ set(check)
177+ end
178+ end
179+
180+ private def set (value : TypeChecker | Error ) : Nil
181+ @result = value
182+ @listener .try(& .call(value))
183+ end
184+
185+ private def map_error (item : T | Error , & : T - > R ) : R | Error forall T , R
186+ case item
187+ in Error
188+ item
189+ in T
190+ yield item
191+ end
126192 end
127- end
193+ end
194+ end
0 commit comments