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.

Files changed (29) hide show
  1. jaclang/compiler/absyntree.py +2 -36
  2. jaclang/compiler/compile.py +21 -0
  3. jaclang/compiler/passes/main/__init__.py +2 -2
  4. jaclang/compiler/passes/main/def_impl_match_pass.py +1 -5
  5. jaclang/compiler/passes/main/def_use_pass.py +14 -7
  6. jaclang/compiler/passes/main/import_pass.py +56 -10
  7. jaclang/compiler/passes/main/pyast_gen_pass.py +55 -2
  8. jaclang/compiler/passes/main/schedules.py +4 -3
  9. jaclang/compiler/passes/main/tests/fixtures/incautoimpl.jac +7 -0
  10. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +4 -4
  11. jaclang/compiler/passes/main/tests/test_import_pass.py +13 -0
  12. jaclang/langserve/engine.py +193 -105
  13. jaclang/langserve/server.py +8 -1
  14. jaclang/langserve/tests/fixtures/circle.jac +73 -0
  15. jaclang/langserve/tests/fixtures/circle_err.jac +73 -0
  16. jaclang/langserve/tests/fixtures/circle_pure.impl.jac +28 -0
  17. jaclang/langserve/tests/fixtures/circle_pure.jac +34 -0
  18. jaclang/langserve/tests/fixtures/circle_pure_err.impl.jac +32 -0
  19. jaclang/langserve/tests/fixtures/circle_pure_err.jac +34 -0
  20. jaclang/langserve/tests/test_server.py +33 -1
  21. jaclang/langserve/utils.py +36 -1
  22. jaclang/tests/fixtures/type_info.jac +1 -1
  23. jaclang/tests/test_cli.py +1 -1
  24. jaclang/utils/helpers.py +3 -5
  25. jaclang/utils/test.py +1 -1
  26. {jaclang-0.7.0.dist-info → jaclang-0.7.1.dist-info}/METADATA +1 -1
  27. {jaclang-0.7.0.dist-info → jaclang-0.7.1.dist-info}/RECORD +29 -22
  28. {jaclang-0.7.0.dist-info → jaclang-0.7.1.dist-info}/WHEEL +0 -0
  29. {jaclang-0.7.0.dist-info → jaclang-0.7.1.dist-info}/entry_points.txt +0 -0
@@ -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 Sequence, Type
7
+ from typing import Optional, Sequence
7
8
 
8
9
 
9
10
  import jaclang.compiler.absyntree as ast
10
- from jaclang.compiler.compile import jac_pass_to_pass, jac_str_to_pass
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.compiler.symtable import Symbol
21
- from jaclang.langserve.utils import sym_tab_list
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, character=warning.loc.col_start
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, doc: TextDocument) -> bool:
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
- def module_reached_pass(self, doc: TextDocument, target: Type[Pass]) -> bool:
97
- """Check if module reached a pass."""
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
- document = self.workspace.get_document(file_path)
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
- if isinstance(build.ir, ast.Module):
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
- document = self.workspace.get_document(file_path)
132
- if self.module_not_diff(document) and self.module_reached_pass(
133
- document, PyBytecodeGenPass
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
- build = jac_pass_to_pass(in_pass=self.modules[file_path].at_pass)
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
- if isinstance(build.ir, ast.Module):
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
- document = self.workspace.get_document(file_path)
151
- if self.module_not_diff(document) and self.module_reached_pass(
152
- document, AccessCheckPass
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
- build = jac_pass_to_pass(
157
- in_pass=self.modules[file_path].at_pass,
158
- target=AccessCheckPass,
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
- if isinstance(build.ir, ast.Module):
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 get_dependencies(
228
- self, file_path: str, deep: bool = False
229
- ) -> list[ast.ModulePath]:
230
- """Return a list of dependencies for a file."""
231
- mod_ir = self.modules[file_path].ir
232
- if deep:
233
- return (
234
- [
235
- i
236
- for i in mod_ir.get_all_sub_nodes(ast.ModulePath)
237
- if i.parent_of_type(ast.Import).hint.tag.value == "jac"
238
- ]
239
- if mod_ir
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 get_symbols(self, file_path: str) -> list[Symbol]:
255
- """Return a list of symbols for a file."""
256
- symbols = []
257
- mod_ir = self.modules[file_path].ir
258
- if file_path in self.modules:
259
- root_table = mod_ir.sym_tab if mod_ir else None
260
- if file_path in self.modules and root_table:
261
- for i in sym_tab_list(sym_tab=root_table, file_path=file_path):
262
- symbols += list(i.tab.values())
263
- return symbols
264
-
265
- def get_definitions(
266
- self, file_path: str
267
- ) -> Sequence[ast.AstSymbolNode]: # need test
268
- """Return a list of definitions for a file."""
269
- defs = []
270
- for i in self.get_symbols(file_path):
271
- defs += i.defn
272
- return defs
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."""
@@ -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
+ }