jaclang 0.7.0__py3-none-any.whl → 0.7.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jaclang might be problematic. Click here for more details.
- jaclang/compiler/absyntree.py +2 -36
- jaclang/compiler/compile.py +21 -0
- jaclang/compiler/passes/main/__init__.py +2 -2
- jaclang/compiler/passes/main/def_impl_match_pass.py +1 -5
- jaclang/compiler/passes/main/def_use_pass.py +14 -7
- jaclang/compiler/passes/main/import_pass.py +56 -10
- jaclang/compiler/passes/main/pyast_gen_pass.py +55 -2
- jaclang/compiler/passes/main/schedules.py +4 -3
- jaclang/compiler/passes/main/tests/fixtures/incautoimpl.jac +7 -0
- jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +4 -4
- jaclang/compiler/passes/main/tests/test_import_pass.py +13 -0
- jaclang/langserve/engine.py +193 -105
- jaclang/langserve/server.py +8 -1
- jaclang/langserve/tests/fixtures/circle.jac +73 -0
- jaclang/langserve/tests/fixtures/circle_err.jac +73 -0
- jaclang/langserve/tests/fixtures/circle_pure.impl.jac +28 -0
- jaclang/langserve/tests/fixtures/circle_pure.jac +34 -0
- jaclang/langserve/tests/fixtures/circle_pure_err.impl.jac +32 -0
- jaclang/langserve/tests/fixtures/circle_pure_err.jac +34 -0
- jaclang/langserve/tests/test_server.py +33 -1
- jaclang/langserve/utils.py +36 -1
- jaclang/tests/fixtures/type_info.jac +1 -1
- jaclang/tests/test_cli.py +1 -1
- jaclang/utils/helpers.py +3 -5
- jaclang/utils/test.py +1 -1
- {jaclang-0.7.0.dist-info → jaclang-0.7.1.dist-info}/METADATA +1 -1
- {jaclang-0.7.0.dist-info → jaclang-0.7.1.dist-info}/RECORD +29 -22
- {jaclang-0.7.0.dist-info → jaclang-0.7.1.dist-info}/WHEEL +0 -0
- {jaclang-0.7.0.dist-info → jaclang-0.7.1.dist-info}/entry_points.txt +0 -0
jaclang/langserve/engine.py
CHANGED
|
@@ -2,57 +2,73 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from enum import IntEnum
|
|
5
6
|
from hashlib import md5
|
|
6
|
-
from typing import
|
|
7
|
+
from typing import Optional, Sequence
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
import jaclang.compiler.absyntree as ast
|
|
10
|
-
from jaclang.compiler.compile import
|
|
11
|
+
from jaclang.compiler.compile import jac_ir_to_pass, jac_str_to_pass
|
|
11
12
|
from jaclang.compiler.parser import JacParser
|
|
12
13
|
from jaclang.compiler.passes import Pass
|
|
13
|
-
from jaclang.compiler.passes.main.schedules import
|
|
14
|
-
AccessCheckPass,
|
|
15
|
-
PyBytecodeGenPass,
|
|
16
|
-
py_code_gen_typed,
|
|
17
|
-
)
|
|
14
|
+
from jaclang.compiler.passes.main.schedules import type_checker_sched
|
|
18
15
|
from jaclang.compiler.passes.tool import FuseCommentsPass, JacFormatPass
|
|
19
16
|
from jaclang.compiler.passes.transform import Alert
|
|
20
|
-
from jaclang.
|
|
21
|
-
from jaclang.
|
|
17
|
+
from jaclang.langserve.utils import find_deepest_node_at_pos
|
|
18
|
+
from jaclang.vendor.pygls import uris
|
|
22
19
|
from jaclang.vendor.pygls.server import LanguageServer
|
|
23
|
-
from jaclang.vendor.pygls.workspace.text_document import TextDocument
|
|
24
20
|
|
|
25
21
|
import lsprotocol.types as lspt
|
|
26
22
|
|
|
27
23
|
|
|
24
|
+
class ALev(IntEnum):
|
|
25
|
+
"""Analysis Level."""
|
|
26
|
+
|
|
27
|
+
QUICK = 1
|
|
28
|
+
DEEP = 2
|
|
29
|
+
TYPE = 3
|
|
30
|
+
|
|
31
|
+
|
|
28
32
|
class ModuleInfo:
|
|
29
33
|
"""Module IR and Stats."""
|
|
30
34
|
|
|
31
35
|
def __init__(
|
|
32
36
|
self,
|
|
33
37
|
ir: ast.Module,
|
|
34
|
-
to_pass: Pass,
|
|
35
38
|
errors: Sequence[Alert],
|
|
36
39
|
warnings: Sequence[Alert],
|
|
40
|
+
alev: ALev,
|
|
41
|
+
parent: Optional[ModuleInfo] = None,
|
|
37
42
|
) -> None:
|
|
38
43
|
"""Initialize module info."""
|
|
39
44
|
self.ir = ir
|
|
40
|
-
self.at_pass = to_pass
|
|
41
45
|
self.errors = errors
|
|
42
46
|
self.warnings = warnings
|
|
47
|
+
self.alev = alev
|
|
48
|
+
self.parent: Optional[ModuleInfo] = parent
|
|
43
49
|
self.diagnostics = self.gen_diagnostics()
|
|
44
50
|
|
|
51
|
+
@property
|
|
52
|
+
def uri(self) -> str:
|
|
53
|
+
"""Return uri."""
|
|
54
|
+
return uris.from_fs_path(self.ir.loc.mod_path)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def has_syntax_error(self) -> bool:
|
|
58
|
+
"""Return if there are syntax errors."""
|
|
59
|
+
return len(self.errors) > 0 and self.alev == ALev.QUICK
|
|
60
|
+
|
|
45
61
|
def gen_diagnostics(self) -> list[lspt.Diagnostic]:
|
|
46
62
|
"""Return diagnostics."""
|
|
47
63
|
return [
|
|
48
64
|
lspt.Diagnostic(
|
|
49
65
|
range=lspt.Range(
|
|
50
66
|
start=lspt.Position(
|
|
51
|
-
line=error.loc.first_line, character=error.loc.col_start
|
|
67
|
+
line=error.loc.first_line - 1, character=error.loc.col_start - 1
|
|
52
68
|
),
|
|
53
69
|
end=lspt.Position(
|
|
54
|
-
line=error.loc.last_line,
|
|
55
|
-
character=error.loc.col_end,
|
|
70
|
+
line=error.loc.last_line - 1,
|
|
71
|
+
character=error.loc.col_end - 1,
|
|
56
72
|
),
|
|
57
73
|
),
|
|
58
74
|
message=error.msg,
|
|
@@ -63,11 +79,12 @@ class ModuleInfo:
|
|
|
63
79
|
lspt.Diagnostic(
|
|
64
80
|
range=lspt.Range(
|
|
65
81
|
start=lspt.Position(
|
|
66
|
-
line=warning.loc.first_line,
|
|
82
|
+
line=warning.loc.first_line - 1,
|
|
83
|
+
character=warning.loc.col_start - 1,
|
|
67
84
|
),
|
|
68
85
|
end=lspt.Position(
|
|
69
|
-
line=warning.loc.last_line,
|
|
70
|
-
character=warning.loc.col_end,
|
|
86
|
+
line=warning.loc.last_line - 1,
|
|
87
|
+
character=warning.loc.col_end - 1,
|
|
71
88
|
),
|
|
72
89
|
),
|
|
73
90
|
message=warning.msg,
|
|
@@ -85,18 +102,17 @@ class JacLangServer(LanguageServer):
|
|
|
85
102
|
super().__init__("jac-lsp", "v0.1")
|
|
86
103
|
self.modules: dict[str, ModuleInfo] = {}
|
|
87
104
|
|
|
88
|
-
def module_not_diff(self,
|
|
105
|
+
def module_not_diff(self, uri: str, alev: ALev) -> bool:
|
|
89
106
|
"""Check if module was changed."""
|
|
107
|
+
doc = self.workspace.get_document(uri)
|
|
90
108
|
return (
|
|
91
109
|
doc.uri in self.modules
|
|
92
110
|
and self.modules[doc.uri].ir.source.hash
|
|
93
111
|
== md5(doc.source.encode()).hexdigest()
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return doc.uri in self.modules and isinstance(
|
|
99
|
-
self.modules[doc.uri].at_pass, target
|
|
112
|
+
and (
|
|
113
|
+
self.modules[doc.uri].alev >= alev
|
|
114
|
+
or self.modules[doc.uri].has_syntax_error
|
|
115
|
+
)
|
|
100
116
|
)
|
|
101
117
|
|
|
102
118
|
def push_diagnostics(self, file_path: str) -> None:
|
|
@@ -107,66 +123,81 @@ class JacLangServer(LanguageServer):
|
|
|
107
123
|
self.modules[file_path].diagnostics,
|
|
108
124
|
)
|
|
109
125
|
|
|
126
|
+
def unwind_to_parent(self, file_path: str) -> str:
|
|
127
|
+
"""Unwind to parent."""
|
|
128
|
+
if file_path in self.modules:
|
|
129
|
+
while cur := self.modules[file_path].parent:
|
|
130
|
+
file_path = cur.uri
|
|
131
|
+
return file_path
|
|
132
|
+
|
|
133
|
+
def update_modules(self, file_path: str, build: Pass, alev: ALev) -> None:
|
|
134
|
+
"""Update modules."""
|
|
135
|
+
if not isinstance(build.ir, ast.Module):
|
|
136
|
+
self.log_error("Error with module build.")
|
|
137
|
+
return
|
|
138
|
+
self.modules[file_path] = ModuleInfo(
|
|
139
|
+
ir=build.ir,
|
|
140
|
+
errors=[
|
|
141
|
+
i
|
|
142
|
+
for i in build.errors_had
|
|
143
|
+
if i.loc.mod_path == uris.to_fs_path(file_path)
|
|
144
|
+
],
|
|
145
|
+
warnings=[
|
|
146
|
+
i
|
|
147
|
+
for i in build.warnings_had
|
|
148
|
+
if i.loc.mod_path == uris.to_fs_path(file_path)
|
|
149
|
+
],
|
|
150
|
+
alev=alev,
|
|
151
|
+
)
|
|
152
|
+
for p in build.ir.mod_deps.keys():
|
|
153
|
+
uri = uris.from_fs_path(p)
|
|
154
|
+
self.modules[uri] = ModuleInfo(
|
|
155
|
+
ir=build.ir.mod_deps[p],
|
|
156
|
+
errors=[i for i in build.errors_had if i.loc.mod_path == p],
|
|
157
|
+
warnings=[i for i in build.warnings_had if i.loc.mod_path == p],
|
|
158
|
+
alev=alev,
|
|
159
|
+
)
|
|
160
|
+
|
|
110
161
|
def quick_check(self, file_path: str) -> None:
|
|
111
162
|
"""Rebuild a file."""
|
|
112
|
-
|
|
113
|
-
if self.module_not_diff(document):
|
|
163
|
+
if self.module_not_diff(file_path, ALev.QUICK):
|
|
114
164
|
return
|
|
115
165
|
try:
|
|
166
|
+
document = self.workspace.get_document(file_path)
|
|
116
167
|
build = jac_str_to_pass(
|
|
117
168
|
jac_str=document.source, file_path=document.path, schedule=[]
|
|
118
169
|
)
|
|
119
170
|
except Exception as e:
|
|
120
171
|
self.log_error(f"Error during syntax check: {e}")
|
|
121
|
-
|
|
122
|
-
self.modules[file_path] = ModuleInfo(
|
|
123
|
-
ir=build.ir,
|
|
124
|
-
to_pass=build,
|
|
125
|
-
errors=build.errors_had,
|
|
126
|
-
warnings=build.warnings_had,
|
|
127
|
-
)
|
|
172
|
+
self.update_modules(file_path, build, ALev.QUICK)
|
|
128
173
|
|
|
129
174
|
def deep_check(self, file_path: str) -> None:
|
|
130
175
|
"""Rebuild a file and its dependencies."""
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
):
|
|
176
|
+
if file_path in self.modules:
|
|
177
|
+
self.quick_check(file_path)
|
|
178
|
+
if self.module_not_diff(file_path, ALev.DEEP):
|
|
135
179
|
return
|
|
136
180
|
try:
|
|
137
|
-
|
|
181
|
+
file_path = self.unwind_to_parent(file_path)
|
|
182
|
+
build = jac_ir_to_pass(ir=self.modules[file_path].ir)
|
|
138
183
|
except Exception as e:
|
|
139
184
|
self.log_error(f"Error during syntax check: {e}")
|
|
140
|
-
|
|
141
|
-
self.modules[file_path] = ModuleInfo(
|
|
142
|
-
ir=build.ir,
|
|
143
|
-
to_pass=build,
|
|
144
|
-
errors=build.errors_had,
|
|
145
|
-
warnings=build.warnings_had,
|
|
146
|
-
)
|
|
185
|
+
self.update_modules(file_path, build, ALev.DEEP)
|
|
147
186
|
|
|
148
187
|
def type_check(self, file_path: str) -> None:
|
|
149
188
|
"""Rebuild a file and its dependencies."""
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
):
|
|
189
|
+
if file_path not in self.modules:
|
|
190
|
+
self.deep_check(file_path)
|
|
191
|
+
if self.module_not_diff(file_path, ALev.TYPE):
|
|
154
192
|
return
|
|
155
193
|
try:
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
schedule=py_code_gen_typed,
|
|
194
|
+
file_path = self.unwind_to_parent(file_path)
|
|
195
|
+
build = jac_ir_to_pass(
|
|
196
|
+
ir=self.modules[file_path].ir, schedule=type_checker_sched
|
|
160
197
|
)
|
|
161
198
|
except Exception as e:
|
|
162
199
|
self.log_error(f"Error during type check: {e}")
|
|
163
|
-
|
|
164
|
-
self.modules[file_path] = ModuleInfo(
|
|
165
|
-
ir=build.ir,
|
|
166
|
-
to_pass=build,
|
|
167
|
-
errors=build.errors_had,
|
|
168
|
-
warnings=build.warnings_had,
|
|
169
|
-
)
|
|
200
|
+
self.update_modules(file_path, build, ALev.TYPE)
|
|
170
201
|
|
|
171
202
|
def get_completion(
|
|
172
203
|
self, file_path: str, position: lspt.Position
|
|
@@ -224,52 +255,109 @@ class JacLangServer(LanguageServer):
|
|
|
224
255
|
)
|
|
225
256
|
]
|
|
226
257
|
|
|
227
|
-
def
|
|
228
|
-
self, file_path: str,
|
|
229
|
-
) ->
|
|
230
|
-
"""Return
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
else []
|
|
241
|
-
)
|
|
242
|
-
else:
|
|
243
|
-
return (
|
|
244
|
-
[
|
|
245
|
-
i
|
|
246
|
-
for i in mod_ir.get_all_sub_nodes(ast.ModulePath)
|
|
247
|
-
if i.loc.mod_path == file_path
|
|
248
|
-
and i.parent_of_type(ast.Import).hint.tag.value == "jac"
|
|
249
|
-
]
|
|
250
|
-
if mod_ir
|
|
251
|
-
else []
|
|
258
|
+
def get_hover_info(
|
|
259
|
+
self, file_path: str, position: lspt.Position
|
|
260
|
+
) -> Optional[lspt.Hover]:
|
|
261
|
+
"""Return hover information for a file."""
|
|
262
|
+
node_selected = find_deepest_node_at_pos(
|
|
263
|
+
self.modules[file_path].ir, position.line, position.character
|
|
264
|
+
)
|
|
265
|
+
value = self.get_node_info(node_selected) if node_selected else None
|
|
266
|
+
if value:
|
|
267
|
+
return lspt.Hover(
|
|
268
|
+
contents=lspt.MarkupContent(
|
|
269
|
+
kind=lspt.MarkupKind.PlainText, value=f"{value}"
|
|
270
|
+
),
|
|
252
271
|
)
|
|
272
|
+
return None
|
|
253
273
|
|
|
254
|
-
def
|
|
255
|
-
"""
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
274
|
+
def get_node_info(self, node: ast.AstNode) -> Optional[str]:
|
|
275
|
+
"""Extract meaningful information from the AST node."""
|
|
276
|
+
try:
|
|
277
|
+
if isinstance(node, ast.Token):
|
|
278
|
+
if isinstance(node, ast.AstSymbolNode):
|
|
279
|
+
if isinstance(node, ast.String):
|
|
280
|
+
return None
|
|
281
|
+
if node.sym_link and node.sym_link.decl:
|
|
282
|
+
decl_node = node.sym_link.decl
|
|
283
|
+
if isinstance(decl_node, ast.Architype):
|
|
284
|
+
if decl_node.doc:
|
|
285
|
+
node_info = f"({decl_node.arch_type.value}) {node.value} \n{decl_node.doc.lit_value}"
|
|
286
|
+
else:
|
|
287
|
+
node_info = (
|
|
288
|
+
f"({decl_node.arch_type.value}) {node.value}"
|
|
289
|
+
)
|
|
290
|
+
if decl_node.semstr:
|
|
291
|
+
node_info += f"\n{decl_node.semstr.lit_value}"
|
|
292
|
+
elif isinstance(decl_node, ast.Ability):
|
|
293
|
+
node_info = f"(ability) can {node.value}"
|
|
294
|
+
if decl_node.signature:
|
|
295
|
+
node_info += f" {decl_node.signature.unparse()}"
|
|
296
|
+
if decl_node.doc:
|
|
297
|
+
node_info += f"\n{decl_node.doc.lit_value}"
|
|
298
|
+
if decl_node.semstr:
|
|
299
|
+
node_info += f"\n{decl_node.semstr.lit_value}"
|
|
300
|
+
elif isinstance(decl_node, ast.Name):
|
|
301
|
+
if (
|
|
302
|
+
decl_node.parent
|
|
303
|
+
and isinstance(decl_node.parent, ast.SubNodeList)
|
|
304
|
+
and decl_node.parent.parent
|
|
305
|
+
and isinstance(decl_node.parent.parent, ast.Assignment)
|
|
306
|
+
and decl_node.parent.parent.type_tag
|
|
307
|
+
):
|
|
308
|
+
node_info = (
|
|
309
|
+
f"(variable) {decl_node.value}: "
|
|
310
|
+
f"{decl_node.parent.parent.type_tag.unparse()}"
|
|
311
|
+
)
|
|
312
|
+
if decl_node.parent.parent.semstr:
|
|
313
|
+
node_info += (
|
|
314
|
+
f"\n{decl_node.parent.parent.semstr.lit_value}"
|
|
315
|
+
)
|
|
316
|
+
else:
|
|
317
|
+
if decl_node.value in [
|
|
318
|
+
"str",
|
|
319
|
+
"int",
|
|
320
|
+
"float",
|
|
321
|
+
"bool",
|
|
322
|
+
"bytes",
|
|
323
|
+
"list",
|
|
324
|
+
"tuple",
|
|
325
|
+
"set",
|
|
326
|
+
"dict",
|
|
327
|
+
"type",
|
|
328
|
+
]:
|
|
329
|
+
node_info = f"({decl_node.value}) Built-in type"
|
|
330
|
+
else:
|
|
331
|
+
node_info = f"(variable) {decl_node.value}: None"
|
|
332
|
+
elif isinstance(decl_node, ast.HasVar):
|
|
333
|
+
if decl_node.type_tag:
|
|
334
|
+
node_info = f"(variable) {decl_node.name.value} {decl_node.type_tag.unparse()}"
|
|
335
|
+
else:
|
|
336
|
+
node_info = f"(variable) {decl_node.name.value}"
|
|
337
|
+
if decl_node.semstr:
|
|
338
|
+
node_info += f"\n{decl_node.semstr.lit_value}"
|
|
339
|
+
elif isinstance(decl_node, ast.ParamVar):
|
|
340
|
+
if decl_node.type_tag:
|
|
341
|
+
node_info = f"(parameter) {decl_node.name.value} {decl_node.type_tag.unparse()}"
|
|
342
|
+
else:
|
|
343
|
+
node_info = f"(parameter) {decl_node.name.value}"
|
|
344
|
+
if decl_node.semstr:
|
|
345
|
+
node_info += f"\n{decl_node.semstr.lit_value}"
|
|
346
|
+
elif isinstance(decl_node, ast.ModuleItem):
|
|
347
|
+
node_info = (
|
|
348
|
+
f"(ModuleItem) {node.value}" # TODO: Add more info
|
|
349
|
+
)
|
|
350
|
+
else:
|
|
351
|
+
node_info = f"{node.value}"
|
|
352
|
+
else:
|
|
353
|
+
node_info = f"{node.value}" # non symbol node
|
|
354
|
+
else:
|
|
355
|
+
return None
|
|
356
|
+
else:
|
|
357
|
+
return None
|
|
358
|
+
except AttributeError as e:
|
|
359
|
+
self.log_warning(f"Attribute error when accessing node attributes: {e}")
|
|
360
|
+
return node_info.strip()
|
|
273
361
|
|
|
274
362
|
def log_error(self, message: str) -> None:
|
|
275
363
|
"""Log an error message."""
|
jaclang/langserve/server.py
CHANGED
|
@@ -29,7 +29,6 @@ def analyze_and_publish(ls: JacLangServer, uri: str) -> None:
|
|
|
29
29
|
|
|
30
30
|
analysis_thread = threading.Thread(target=run_analysis)
|
|
31
31
|
analysis_thread.start()
|
|
32
|
-
ls.log_info("Analysis restarted")
|
|
33
32
|
|
|
34
33
|
|
|
35
34
|
def stop_analysis() -> None:
|
|
@@ -130,6 +129,14 @@ def formatting(
|
|
|
130
129
|
return ls.formatted_jac(params.text_document.uri)
|
|
131
130
|
|
|
132
131
|
|
|
132
|
+
@server.feature(lspt.TEXT_DOCUMENT_HOVER, lspt.HoverOptions(work_done_progress=True))
|
|
133
|
+
def hover(
|
|
134
|
+
ls: JacLangServer, params: lspt.TextDocumentPositionParams
|
|
135
|
+
) -> Optional[lspt.Hover]:
|
|
136
|
+
"""Provide hover information for the given hover request."""
|
|
137
|
+
return ls.get_hover_info(params.text_document.uri, params.position)
|
|
138
|
+
|
|
139
|
+
|
|
133
140
|
def run_lang_server() -> None:
|
|
134
141
|
"""Run the language server."""
|
|
135
142
|
server.start_io()
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module demonstrates a simple circle class and a function to calculate
|
|
3
|
+
the area of a circle in all of Jac's glory.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import:py math;
|
|
7
|
+
# Module-level global var
|
|
8
|
+
|
|
9
|
+
glob RAD = 5;
|
|
10
|
+
|
|
11
|
+
"""Function to calculate the area of a circle."""
|
|
12
|
+
can calculate_area(radius: float) -> float {
|
|
13
|
+
return math.pi * radius * radius;
|
|
14
|
+
}
|
|
15
|
+
#* (This is multiline comments in Jac)
|
|
16
|
+
Above we have the demonstration of a function to calculate the area of a circle.
|
|
17
|
+
Below we have the demonstration of a class to calculate the area of a circle.
|
|
18
|
+
*#
|
|
19
|
+
|
|
20
|
+
"""Enum for shape types"""
|
|
21
|
+
enum ShapeType {
|
|
22
|
+
CIRCLE="Circle",
|
|
23
|
+
UNKNOWN="Unknown"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
"""Base class for a shape."""
|
|
27
|
+
obj Shape {
|
|
28
|
+
has shape_type: ShapeType;
|
|
29
|
+
|
|
30
|
+
"""Abstract method to calculate the area of a shape."""
|
|
31
|
+
can area -> float abs;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
"""Circle class inherits from Shape."""
|
|
35
|
+
obj Circle :Shape: {
|
|
36
|
+
can init(radius: float) {
|
|
37
|
+
super.init(ShapeType.CIRCLE);
|
|
38
|
+
self.radius = radius;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
"""Overridden method to calculate the area of the circle."""
|
|
42
|
+
override can area -> float {
|
|
43
|
+
return math.pi * self.radius * self.radius;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
with entry {
|
|
48
|
+
c = Circle(RAD);
|
|
49
|
+
}
|
|
50
|
+
# Global also works here
|
|
51
|
+
|
|
52
|
+
with entry:__main__ {
|
|
53
|
+
# To run the program functionality
|
|
54
|
+
print(f"Area of a circle with radius {RAD} using function: {calculate_area(RAD)}");
|
|
55
|
+
print(f"Area of a {c.shape_type.value} with radius {RAD} using class: {c.area()}");
|
|
56
|
+
}
|
|
57
|
+
# Unit Tests!
|
|
58
|
+
|
|
59
|
+
glob expected_area = 78.53981633974483;
|
|
60
|
+
|
|
61
|
+
test calc_area {
|
|
62
|
+
check.assertAlmostEqual(calculate_area(RAD), expected_area);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
test circle_area {
|
|
66
|
+
c = Circle(RAD);
|
|
67
|
+
check.assertAlmostEqual(c.area(), expected_area);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
test circle_type {
|
|
71
|
+
c = Circle(RAD);
|
|
72
|
+
check.assertEqual(c.shape_type, ShapeType.CIRCLE);
|
|
73
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module demonstrates a simple circle class and a function to calculate
|
|
3
|
+
the area of a circle in all of Jac's glory.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import:py math;
|
|
7
|
+
# Module-level global var
|
|
8
|
+
|
|
9
|
+
glob RAD = 5;
|
|
10
|
+
|
|
11
|
+
"""Function to calculate the area of a circle."""
|
|
12
|
+
can calculate_area(radius: float) -> float {
|
|
13
|
+
return math.pi * radius * radius;
|
|
14
|
+
}
|
|
15
|
+
#* (This is multiline comments in Jac)
|
|
16
|
+
Above we have the demonstration of a function to calculate the area of a circle.
|
|
17
|
+
Below we have the demonstration of a class to calculate the area of a circle.
|
|
18
|
+
*#
|
|
19
|
+
|
|
20
|
+
"""Enum for shape types"""
|
|
21
|
+
enum ShapeType {
|
|
22
|
+
CIRCLE="Circle"
|
|
23
|
+
UNKNOWN="Unknown"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
"""Base class for a shape."""
|
|
27
|
+
obj Shape {
|
|
28
|
+
has shape_type: ShapeType;
|
|
29
|
+
|
|
30
|
+
"""Abstract method to calculate the area of a shape."""
|
|
31
|
+
can area -> float abs;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
"""Circle class inherits from Shape."""
|
|
35
|
+
obj Circle :Shape: {
|
|
36
|
+
can init(radius: float) {
|
|
37
|
+
super.init(ShapeType.CIRCLE);
|
|
38
|
+
self.radius = radius;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
"""Overridden method to calculate the area of the circle."""
|
|
42
|
+
override can area -> float {
|
|
43
|
+
return math.pi * self.radius * self.radius;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
with entry {
|
|
48
|
+
c = Circle(RAD);
|
|
49
|
+
}
|
|
50
|
+
# Global also works here
|
|
51
|
+
|
|
52
|
+
with entry:__main__ {
|
|
53
|
+
# To run the program functionality
|
|
54
|
+
print(f"Area of a circle with radius {RAD} using function: {calculate_area(RAD)}");
|
|
55
|
+
print(f"Area of a {c.shape_type.value} with radius {RAD} using class: {c.area()}");
|
|
56
|
+
}
|
|
57
|
+
# Unit Tests!
|
|
58
|
+
|
|
59
|
+
glob expected_area = 78.53981633974483;
|
|
60
|
+
|
|
61
|
+
test calc_area {
|
|
62
|
+
check.assertAlmostEqual(calculate_area(RAD), expected_area);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
test circle_area {
|
|
66
|
+
c = Circle(RAD);
|
|
67
|
+
check.assertAlmostEqual(c.area(), expected_area);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
test circle_type {
|
|
71
|
+
c = Circle(RAD);
|
|
72
|
+
check.assertEqual(c.shape_type, ShapeType.CIRCLE);
|
|
73
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Enum for shape types"""
|
|
2
|
+
|
|
3
|
+
:enum:ShapeType {
|
|
4
|
+
CIRCLE="Circle",
|
|
5
|
+
UNKNOWN="Unknown"
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
"""Function to calculate the area of a circle."""
|
|
9
|
+
:can:calculate_area
|
|
10
|
+
(radius: float) -> float {
|
|
11
|
+
return math.pi * radius * radius;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:obj:Circle:can:init
|
|
15
|
+
(radius: float) {
|
|
16
|
+
self.radius = radius;
|
|
17
|
+
super.init(ShapeType.CIRCLE);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
"""Overridden method to calculate the area of the circle."""
|
|
21
|
+
:obj:Circle:can:area -> float {
|
|
22
|
+
return math.pi * self.radius * self.radius;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:can:main_run {
|
|
26
|
+
print(f"Area of a circle with radius {RAD} using function: {calculate_area(RAD)}");
|
|
27
|
+
print(f"Area of a {c.shape_type.value} with radius {RAD} using class: {c.area()}");
|
|
28
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module demonstrates a simple circle class and a function to calculate
|
|
3
|
+
the area of a circle in all of Jac's glory.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import:py math;
|
|
7
|
+
|
|
8
|
+
enum ShapeType;
|
|
9
|
+
|
|
10
|
+
can calculate_area(radius: float) -> float;
|
|
11
|
+
can main_run;
|
|
12
|
+
|
|
13
|
+
"""Base class for a shape."""
|
|
14
|
+
obj Shape {
|
|
15
|
+
has shape_type: ShapeType;
|
|
16
|
+
|
|
17
|
+
can area -> float abs;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
"""Circle class inherits from Shape."""
|
|
21
|
+
obj Circle :Shape: {
|
|
22
|
+
has radius: float;
|
|
23
|
+
|
|
24
|
+
can init(radius: float);
|
|
25
|
+
can area -> float;
|
|
26
|
+
}
|
|
27
|
+
# Radius of the demo circle
|
|
28
|
+
|
|
29
|
+
glob RAD = 5, c = Circle(radius=RAD);
|
|
30
|
+
|
|
31
|
+
"""Here we run the main program."""
|
|
32
|
+
with entry:__main__ {
|
|
33
|
+
main_run();
|
|
34
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Enum for shape types"""
|
|
2
|
+
|
|
3
|
+
:enum:ShapeType {
|
|
4
|
+
CIRCLE = "Circle",
|
|
5
|
+
UNKNOWN = "Unknown"
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
"""Function to calculate the area of a circle."""
|
|
9
|
+
:can:calculate_area
|
|
10
|
+
(radius: float) -> float {
|
|
11
|
+
return math.pi * radius * radius;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:obj:Circle:can:init
|
|
15
|
+
(radius: float) {
|
|
16
|
+
self.radius = radius;
|
|
17
|
+
super.init(ShapeType.CIRCLE);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
"""Overridden method to calculate the area of the circle."""
|
|
21
|
+
:obj:Circle:can:area -> float {
|
|
22
|
+
return math.pi * self.radius * self.radius;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:can:main_run {
|
|
26
|
+
print(
|
|
27
|
+
f"Area of a circle with radius {RAD} using function: {calculate_area(RAD)}"
|
|
28
|
+
);
|
|
29
|
+
print(
|
|
30
|
+
f"Area of a {c.shape_type.value} with radius {RAD} using class: {c.area()}"
|
|
31
|
+
);
|
|
32
|
+
}
|