Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto import builtin in jac files, support BuiltinType in fuse type info #1267

Merged
merged 8 commits into from
Sep 15, 2024
2 changes: 1 addition & 1 deletion jac/jaclang/compiler/absyntree.py
Original file line number Diff line number Diff line change
Expand Up @@ -4212,7 +4212,7 @@ def lit_value(
raise NotImplementedError


class BuiltinType(Name, Literal, NameAtom):
class BuiltinType(Name, Literal):
"""Type node type for Jac Ast."""

SYMBOL_TYPE = SymbolType.VAR
Expand Down
48 changes: 35 additions & 13 deletions jac/jaclang/compiler/passes/main/fuse_typeinfo_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from __future__ import annotations

import re
from typing import Callable, Optional, TypeVar

import jaclang.compiler.absyntree as ast
Expand Down Expand Up @@ -46,24 +47,24 @@ def __call_type_handler(
)

def __set_sym_table_link(self, node: ast.AstSymbolNode) -> None:
typ = node.sym_type.split(".")
typ_sym_table = self.ir.sym_tab
assert isinstance(self.ir, ast.Module)

if typ[0] == "builtins":
return
sym_type = node.sym_type
if re.match(r"builtins.(list|dict|tuple)", sym_type):
sym_type = re.sub(r"\[.*\]", "", sym_type)

typ = sym_type.split(".")

if node.sym_type == "types.ModuleType" and node.sym:
node.name_spec.type_sym_tab = node.sym.parent_tab.find_scope(node.sym_name)

assert isinstance(self.ir, ast.Module)

if typ_sym_table:
for i in typ:
if i == self.ir.name:
continue
f = typ_sym_table.find_scope(i)
if f:
typ_sym_table = f
for i in typ:
if i == self.ir.name:
continue
f = typ_sym_table.find_scope(i)
if f:
typ_sym_table = f

if typ_sym_table != self.ir.sym_tab:
node.name_spec.type_sym_tab = typ_sym_table
Expand Down Expand Up @@ -144,6 +145,11 @@ def node_handler(self: FuseTypeInfoPass, node: T) -> None:
self.__set_sym_table_link(node)
self.__collect_python_dependencies(node)

# Special handing for BuiltinType
elif isinstance(node, ast.BuiltinType):
func(self, node) # type: ignore
self.__set_sym_table_link(node)

# Jac node doesn't have mypy nodes linked to it
else:
self.__debug_print(
Expand Down Expand Up @@ -209,10 +215,21 @@ def __collect_type_from_symbol(self, node: ast.AstSymbolNode) -> None:
f"{type(mypy_node)}"
)

def __check_builltin_symbol(self, node: ast.NameAtom) -> None:
if isinstance(node.parent, ast.AtomTrailer) and node is node.parent.right:
return
builtins_sym_tab = self.ir.sym_tab.find_scope("builtins")
assert builtins_sym_tab is not None
builtins_sym = builtins_sym_tab.lookup(node.sym_name)
if builtins_sym:
node.name_spec._sym = builtins_sym

@__handle_node
def enter_name(self, node: ast.NameAtom) -> None:
"""Pass handler for name nodes."""
self.__collect_type_from_symbol(node)
if node.sym is None:
self.__check_builltin_symbol(node)

@__handle_node
def enter_module_path(self, node: ast.ModulePath) -> None:
Expand Down Expand Up @@ -423,7 +440,8 @@ def enter_bool(self, node: ast.Bool) -> None:
@__handle_node
def enter_builtin_type(self, node: ast.BuiltinType) -> None:
"""Pass handler for BuiltinType nodes."""
self.__collect_type_from_symbol(node)
self.__check_builltin_symbol(node)
node.name_spec.sym_type = f"builtins.{node.sym_name}"

def get_type_from_instance(
self, node: ast.AstSymbolNode, mypy_type: MypyTypes.Instance
Expand Down Expand Up @@ -552,6 +570,10 @@ def exit_atom_trailer(self, node: ast.AtomTrailer) -> None:
type_symtab: Optional[SymbolTable] = self.ir.sym_tab
assert isinstance(self.ir, ast.Module)
assert isinstance(type_symtab, SymbolTable)

if re.match(r"builtins.(list|dict|tuple)", node_type):
node_type = re.sub(r"\[.*\]", "", node_type)

for j in node_type.split("."):
if j == self.ir.name:
continue
Expand Down
27 changes: 27 additions & 0 deletions jac/jaclang/compiler/passes/main/import_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import ast as py_ast
import os
import pathlib
from typing import Optional


Expand Down Expand Up @@ -200,6 +201,7 @@ class PyImportPass(JacImportPass):
def before_pass(self) -> None:
"""Only run pass if settings are set to raise python."""
super().before_pass()
self.__load_builtins()

def __get_current_module(self, node: ast.AstNode) -> str:
parent = node.find_parent_of_type(ast.Module)
Expand Down Expand Up @@ -296,6 +298,31 @@ def import_py_module(
raise e
return None

def __load_builtins(self) -> None:
"""Pyraise builtins to help with builtins auto complete."""
from jaclang.compiler.passes.main import PyastBuildPass

assert isinstance(self.ir, ast.Module)

file_to_raise = str(
pathlib.Path(os.path.dirname(__file__)).parent.parent.parent
/ "vendor"
/ "mypy"
/ "typeshed"
/ "stdlib"
/ "builtins.pyi"
)
with open(file_to_raise, "r", encoding="utf-8") as f:
mod = PyastBuildPass(
input_ir=ast.PythonModuleAst(
py_ast.parse(f.read()), mod_path=file_to_raise
),
).ir
mod.parent = self.ir
SubNodeTabPass(input_ir=mod, prior=self)
SymTabBuildPass(input_ir=mod, prior=self)
mod.parent = None

def annex_impl(self, node: ast.Module) -> None:
"""Annex impl and test modules."""
return None
18 changes: 0 additions & 18 deletions jac/jaclang/compiler/passes/main/sym_tab_build_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
for globals, imports, architypes, and abilities declarations and definitions.
"""

import builtins

import jaclang.compiler.absyntree as ast
from jaclang.compiler.constant import Tokens as Tok
from jaclang.compiler.passes import Pass
from jaclang.compiler.symtable import SymbolTable

Expand Down Expand Up @@ -54,21 +51,6 @@ def enter_module(self, node: ast.Module) -> None:
"""
self.push_scope(node.name, node)
self.sync_node_to_scope(node)
for obj in dir(builtins):
builtin = ast.Name(
file_path=node.loc.mod_path,
name=Tok.NAME,
value=str(obj),
line=0,
end_line=0,
col_start=0,
col_end=0,
pos_start=0,
pos_end=0,
)
self.sync_node_to_scope(builtin)
builtin.sym_tab.def_insert(builtin)
# self.def_insert(ast.Name.gen_stub_from_node(node.name, "root"))

def exit_module(self, node: ast.Module) -> None:
"""Sub objects.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,6 @@ def test_type_coverage(self) -> None:
self.assertIn("HasVar - species - Type: builtins.str", out)
self.assertIn("myDog - Type: type_info.Dog", out)
self.assertIn("Body - Type: type_info.Dog.Body", out)
self.assertEqual(out.count("Type: builtins.str"), 28)
self.assertEqual(out.count("Type: builtins.str"), 34)
for i in lis:
self.assertNotIn(i, out)
2 changes: 1 addition & 1 deletion jac/jaclang/langserve/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ def get_definition(
),
),
)
elif isinstance(node_selected, (ast.ElementStmt, ast.BuiltinType)):
elif isinstance(node_selected, ast.ElementStmt):
return None
decl_node = (
node_selected.parent.body.target
Expand Down
2 changes: 1 addition & 1 deletion jac/jaclang/langserve/tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def test_sem_tokens(self) -> None:
),
(
"<JacSemTokenType.FUNCTION: 12>, <JacSemTokenModifier.DECLARATION: 1>,",
6,
8,
),
("<JacSemTokenType.METHOD: 13>, <JacSemTokenModifier.DECLARATION: 1>", 6),
("<JacSemTokenType.ENUM: 3>, <JacSemTokenModifier.DECLARATION: 1>,", 4),
Expand Down
16 changes: 16 additions & 0 deletions jac/jaclang/tests/fixtures/builtins_test.jac
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
with entry {
a: list[str] = [];
a.append("str1");
a.append("str2");
a.pop();
a.pop();

str(6).count("6");
int("5");

b: dict[str, list[int]] = {"a": [2, 3, 4]};
b.keys();
b["a"].append(9);

dir(a);
}
31 changes: 29 additions & 2 deletions jac/jaclang/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,33 @@ def test_import_mod_abs_path(self) -> None:
r"8\:37 \- 8:44.*ModuleItem - display - abs_path\:.*fixtures/pygame_mock/display.py",
)

def test_builtins_loading(self) -> None:
"""Testing for print AstTool."""
from jaclang.settings import settings

settings.ast_symbol_info_detailed = True
captured_output = io.StringIO()
sys.stdout = captured_output

cli.tool("ir", ["ast", f"{self.fixture_abs_path('builtins_test.jac')}"])

sys.stdout = sys.__stdout__
stdout_value = captured_output.getvalue()
settings.ast_symbol_info_detailed = False

self.assertRegex(
stdout_value,
r"2\:8 \- 2\:12.*BuiltinType - list - .*SymbolPath: builtins_test.builtins.list",
)
self.assertRegex(
stdout_value,
r"15\:5 \- 15\:8.*Name - dir - .*SymbolPath: builtins_test.builtins.dir",
)
self.assertRegex(
stdout_value,
r"13\:12 \- 13\:18.*Name - append - .*SymbolPath: builtins_test.builtins.list.append",
)

def test_ast_dotgen(self) -> None:
"""Testing for print AstTool."""
captured_output = io.StringIO()
Expand Down Expand Up @@ -218,8 +245,8 @@ def test_type_info(self) -> None:
sys.stdout = sys.__stdout__
stdout_value = captured_output.getvalue()
self.assertEqual(stdout_value.count("type_info.ServerWrapper"), 7)
self.assertEqual(stdout_value.count("builtins.int"), 2)
self.assertEqual(stdout_value.count("builtins.str"), 7)
self.assertEqual(stdout_value.count("builtins.int"), 3)
self.assertEqual(stdout_value.count("builtins.str"), 10)

def test_build_and_run(self) -> None:
"""Testing for print AstTool."""
Expand Down
2 changes: 1 addition & 1 deletion jac/jaclang/utils/treeprinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def __node_repr_in_tree(node: AstNode) -> str:
if node.sym
else "<No Symbol is associated with this node>"
)
out += f" SymbolPath: {symbol}"
out += f", SymbolPath: {symbol}"
return out
elif isinstance(node, Token):
return f"{node.__class__.__name__} - {node.value}, {access}"
Expand Down
Loading