Skip to content

Commit

Permalink
Use a new file tag parser
Browse files Browse the repository at this point in the history
  • Loading branch information
thetarnav committed Aug 30, 2024
1 parent bd60025 commit c69f420
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 110 deletions.
192 changes: 84 additions & 108 deletions src/common/ast.odin
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "core:fmt"
import "core:log"
import "core:mem"
import "core:odin/ast"
import "core:odin/parser"
import path "core:path/slashpath"
import "core:strings"

Expand Down Expand Up @@ -69,16 +70,15 @@ keyword_map: map[string]bool = {
}

GlobalExpr :: struct {
name: string,
name_expr: ^ast.Expr,
expr: ^ast.Expr,
mutable: bool,
docs: ^ast.Comment_Group,
attributes: []^ast.Attribute,
deprecated: bool,
file_private: bool,
package_private: bool,
builtin: bool,
name: string,
name_expr: ^ast.Expr,
expr: ^ast.Expr,
mutable: bool,
docs: ^ast.Comment_Group,
attributes: []^ast.Attribute,
deprecated: bool,
private: parser.Private_Flag,
builtin: bool,
}

get_attribute_objc_type :: proc(attributes: []^ast.Attribute) -> ^ast.Expr {
Expand Down Expand Up @@ -240,116 +240,92 @@ is_expr_basic_lit :: proc(expr: ^ast.Expr) -> bool {
return ok
}

collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^ast.Node, skip_private: bool) {
if value_decl, ok := stmt.derived.(^ast.Value_Decl); ok {
is_deprecated := false
is_private_file := false
is_private_pkg := false
is_builtin := false

for attribute in value_decl.attributes {
for elem in attribute.elems {
if value, ok := elem.derived.(^ast.Field_Value); ok {
if ident, ok := value.field.derived.(^ast.Ident); ok {
switch ident.name {
case "private":
if val, ok := value.value.derived.(^ast.Basic_Lit); ok {
switch val.tok.text {
case "\"file\"":
is_private_file = true
case "package":
is_private_pkg = true
}
} else {
is_private_pkg = true
}
}
}
} else if ident, ok := elem.derived.(^ast.Ident); ok {
switch ident.name {
case "deprecated":
is_deprecated = true
case "builtin":
is_builtin = true
case "private":
is_private_pkg = true
}
}
}
}
collect_value_decl :: proc(
exprs: ^[dynamic]GlobalExpr,
file: ast.File,
file_tags: parser.File_Tags,
stmt: ^ast.Node,
skip_private: bool,
) {
value_decl, is_value_decl := stmt.derived.(^ast.Value_Decl)

if is_private_file && skip_private {
return
}
if !is_value_decl {
return
}

// If a private status is not explicitly set with an attribute above the declaration
// check the file comment.
if !is_private_file && !is_private_pkg && file.docs != nil {
for comment in file.docs.list {
txt := comment.text
if strings.has_prefix(txt, "//+private") {
txt = strings.trim_prefix(txt, "//+private")
is_private_pkg = true

if strings.has_prefix(txt, " ") {
txt = strings.trim_space(txt)
if txt == "file" {
is_private_file = true
}
global_expr := GlobalExpr{
mutable = value_decl.is_mutable,
docs = value_decl.docs,
attributes = value_decl.attributes[:],
private = file_tags.private,
}

for attribute in value_decl.attributes {
for elem in attribute.elems {
ident: ^ast.Ident
value: ast.Any_Node

#partial switch v in elem.derived {
case ^ast.Field_Value:
ident = v.field.derived.(^ast.Ident) or_continue
value = v.value.derived
case ^ast.Ident:
ident = v
case:
continue
}

switch ident.name {
case "deprecated":
global_expr.deprecated = true
case "builtin":
global_expr.builtin = true
case "private":
if val, ok := value.(^ast.Basic_Lit); ok {
switch val.tok.text {
case "\"file\"":
global_expr.private = .File
case "\"package\"":
global_expr.private = .Package
}
} else if strings.has_prefix(txt, "//+build ignore") {
is_private_pkg = true
is_private_file = true
} else {
global_expr.private = .Package
}
}
}
}

for name, i in value_decl.names {
str := get_ast_node_string(name, file.src)

if value_decl.type != nil {
append(
exprs,
GlobalExpr {
name = str,
name_expr = name,
expr = value_decl.type,
mutable = value_decl.is_mutable,
docs = value_decl.docs,
attributes = value_decl.attributes[:],
deprecated = is_deprecated,
builtin = is_builtin,
package_private = is_private_pkg,
},
)
} else {
if len(value_decl.values) > i {
append(
exprs,
GlobalExpr {
name = str,
name_expr = name,
expr = value_decl.values[i],
mutable = value_decl.is_mutable,
docs = value_decl.docs,
attributes = value_decl.attributes[:],
deprecated = is_deprecated,
builtin = is_builtin,
package_private = is_private_pkg,
},
)
}
}
if file_tags.ignore {
global_expr.private = .File
}

if skip_private && global_expr.private == .File {
return
}

for name, i in value_decl.names {
global_expr.name = get_ast_node_string(name, file.src)
global_expr.name_expr = name

if value_decl.type != nil {
global_expr.expr = value_decl.type
append(exprs, global_expr)
} else if len(value_decl.values) > i {
global_expr.expr = value_decl.values[i]
append(exprs, global_expr)
}
}
}

collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
exprs := make([dynamic]GlobalExpr, context.temp_allocator)
defer shrink(&exprs)

file_tags := parser.parse_file_tags(file, context.temp_allocator)

for decl in file.decls {
if value_decl, ok := decl.derived.(^ast.Value_Decl); ok {
collect_value_decl(&exprs, file, decl, skip_private)
collect_value_decl(&exprs, file, file_tags, decl, skip_private)
} else if when_decl, ok := decl.derived.(^ast.When_Stmt); ok {
if when_decl.cond == nil {
continue
Expand Down Expand Up @@ -395,21 +371,21 @@ collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
if allowed {
if block, ok := when_decl.body.derived.(^ast.Block_Stmt); ok {
for stmt in block.stmts {
collect_value_decl(&exprs, file, stmt, skip_private)
collect_value_decl(&exprs, file, file_tags, stmt, skip_private)
}
}
} else if ident.name != "ODIN_OS" && ident.name != "ODIN_ARCH" {
if block, ok := when_decl.body.derived.(^ast.Block_Stmt); ok {
for stmt in block.stmts {
collect_value_decl(&exprs, file, stmt, skip_private)
collect_value_decl(&exprs, file, file_tags, stmt, skip_private)
}
}
}
}
} else {
if block, ok := when_decl.body.derived.(^ast.Block_Stmt); ok {
for stmt in block.stmts {
collect_value_decl(&exprs, file, stmt, skip_private)
collect_value_decl(&exprs, file, file_tags, stmt, skip_private)
}
}
}
Expand All @@ -420,7 +396,7 @@ collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {

if block, ok := foreign_decl.body.derived.(^ast.Block_Stmt); ok {
for stmt in block.stmts {
collect_value_decl(&exprs, file, stmt, skip_private)
collect_value_decl(&exprs, file, file_tags, stmt, skip_private)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/server/collector.odin
Original file line number Diff line number Diff line change
Expand Up @@ -644,11 +644,11 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri
symbol.flags |= {.Deprecated}
}

if expr.file_private {
if expr.private == .File {
symbol.flags |= {.PrivateFile}
}

if expr.package_private {
if expr.private == .Package {
symbol.flags |= {.PrivatePackage}
}

Expand Down
39 changes: 39 additions & 0 deletions tests/completions_test.odin
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tests

import "core:fmt"
import "core:testing"
import "core:strings"

import test "src:testing"

Expand Down Expand Up @@ -1069,6 +1070,44 @@ ast_file_private_completion :: proc(t: ^testing.T) {
test.expect_completion_details(t, &source, ".", {})
}

@(test)
ast_file_tag_private_completion :: proc(t: ^testing.T) {
comments := []string{
"// +private",
"//+private file",
"// +build ignore",
}

for comment in comments {

b := strings.builder_make(context.temp_allocator)

strings.write_string(&b, comment)
strings.write_string(&b, `
package my_package
my_proc :: proc() -> bool {}
`)

source := test.Source {
main = `package main
import "my_package"
main :: proc() {
my_package.{*}
}
`,
packages = {
{
pkg = "my_package",
source = strings.to_string(b),
}
},
}

test.expect_completion_details(t, &source, ".", {})
}
}

@(test)
ast_non_mutable_variable_struct_completion :: proc(t: ^testing.T) {
packages := make([dynamic]test.Package, context.temp_allocator)
Expand Down

0 comments on commit c69f420

Please sign in to comment.