mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: move attributes to declarations (#6026)
This commit is contained in:
parent
3ce6dd6cbc
commit
f238890fe9
@ -15,10 +15,10 @@ pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | C
|
||||
None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf |
|
||||
SqlExpr | StringInterLiteral | StringLiteral | StructInit | Type | TypeOf | UnsafeExpr
|
||||
|
||||
pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | CompFor | CompIf |
|
||||
ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt |
|
||||
GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module |
|
||||
Return | SqlStmt | StructDecl | TypeDecl
|
||||
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | CompIf | ConstDecl |
|
||||
DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl |
|
||||
GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return |
|
||||
SqlStmt | StructDecl | TypeDecl
|
||||
|
||||
pub type ScopeObject = ConstField | GlobalDecl | Var
|
||||
|
||||
@ -36,7 +36,7 @@ pub:
|
||||
// `{stmts}` or `unsafe {stmts}`
|
||||
pub struct Block {
|
||||
pub:
|
||||
stmts []Stmt
|
||||
stmts []Stmt
|
||||
is_unsafe bool
|
||||
}
|
||||
|
||||
@ -129,7 +129,7 @@ pub:
|
||||
comments []Comment
|
||||
default_expr Expr
|
||||
has_default_expr bool
|
||||
attrs []string
|
||||
attrs []table.Attr
|
||||
is_public bool
|
||||
pub mut:
|
||||
typ table.Type
|
||||
@ -174,7 +174,7 @@ pub:
|
||||
pub_mut_pos int // pub mut:
|
||||
language table.Language
|
||||
is_union bool
|
||||
attrs []string
|
||||
attrs []table.Attr
|
||||
end_comments []Comment
|
||||
}
|
||||
|
||||
@ -224,9 +224,9 @@ pub enum ImportSymbolKind {
|
||||
|
||||
pub struct ImportSymbol {
|
||||
pub:
|
||||
pos token.Position
|
||||
name string
|
||||
kind ImportSymbolKind
|
||||
pos token.Position
|
||||
name string
|
||||
kind ImportSymbolKind
|
||||
}
|
||||
|
||||
pub struct AnonFn {
|
||||
@ -253,11 +253,11 @@ pub:
|
||||
language table.Language
|
||||
no_body bool // just a definition `fn C.malloc()`
|
||||
is_builtin bool // this function is defined in builtin/strconv
|
||||
ctdefine string // has [if myflag] tag
|
||||
pos token.Position
|
||||
body_pos token.Position
|
||||
file string
|
||||
is_generic bool
|
||||
attrs []table.Attr
|
||||
pub mut:
|
||||
stmts []Stmt
|
||||
return_type table.Type
|
||||
@ -537,6 +537,7 @@ pub enum CompIfKind {
|
||||
platform
|
||||
typecheck
|
||||
}
|
||||
|
||||
pub struct CompIf {
|
||||
pub:
|
||||
val string
|
||||
@ -641,22 +642,6 @@ pub mut:
|
||||
expr_type table.Type
|
||||
}
|
||||
|
||||
// e.g. `[unsafe_fn]`
|
||||
pub struct Attr {
|
||||
pub:
|
||||
name string
|
||||
is_string bool // `['xxx']`
|
||||
}
|
||||
|
||||
pub fn (attrs []Attr) contains(attr Attr) bool {
|
||||
for a in attrs {
|
||||
if attr.name == a.name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pub struct EnumVal {
|
||||
pub:
|
||||
enum_name string
|
||||
|
@ -196,10 +196,13 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool {
|
||||
c.warn('function `$stmt.name` $no_pub_in_main_warning', stmt.pos)
|
||||
}
|
||||
}
|
||||
if stmt.ctdefine.len > 0 {
|
||||
if stmt.return_type != table.void_type {
|
||||
c.error('only functions that do NOT return values can have `[if $stmt.ctdefine]` tags',
|
||||
stmt.pos)
|
||||
if stmt.return_type != table.void_type {
|
||||
for attr in stmt.attrs {
|
||||
if attr.is_ctdefine {
|
||||
c.error('only functions that do NOT return values can have `[if $attr.name]` tags',
|
||||
stmt.pos)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1938,7 +1941,6 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||
ast.AssignStmt {
|
||||
c.assign_stmt(mut node)
|
||||
}
|
||||
ast.Attr {}
|
||||
ast.Block {
|
||||
if node.is_unsafe {
|
||||
assert !c.inside_unsafe
|
||||
@ -3300,8 +3302,7 @@ fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) table.Type {
|
||||
|
||||
fn (mut c Checker) fetch_and_verify_orm_fields(info table.Struct, pos token.Position, table_name string) []table.Field {
|
||||
fields := info.fields.filter(it.typ in
|
||||
[table.string_type, table.int_type, table.bool_type] &&
|
||||
'skip' !in it.attrs)
|
||||
[table.string_type, table.int_type, table.bool_type] && !it.attrs.contains('skip'))
|
||||
if fields.len == 0 {
|
||||
c.error('V orm: select: empty fields in `$table_name`', pos)
|
||||
}
|
||||
|
@ -286,13 +286,6 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
|
||||
f.expr(node.expr)
|
||||
f.writeln('')
|
||||
}
|
||||
ast.Attr {
|
||||
if node.is_string {
|
||||
f.writeln("['$node.name']")
|
||||
} else {
|
||||
f.writeln('[$node.name]')
|
||||
}
|
||||
}
|
||||
ast.Block {
|
||||
if node.is_unsafe {
|
||||
f.write('unsafe ')
|
||||
@ -593,6 +586,7 @@ pub fn (mut f Fmt) type_decl(node ast.TypeDecl) {
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
|
||||
f.attrs(node.attrs)
|
||||
if node.is_pub {
|
||||
f.write('pub ')
|
||||
}
|
||||
@ -630,9 +624,7 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
|
||||
f.write('\t$field.name ')
|
||||
f.write(strings.repeat(` `, max - field.name.len))
|
||||
f.write(f.type_to_str(field.typ))
|
||||
if field.attrs.len > 0 {
|
||||
f.write(' [' + field.attrs.join(';') + ']')
|
||||
}
|
||||
f.inline_attrs(field.attrs)
|
||||
if field.has_default_expr {
|
||||
f.write(' = ')
|
||||
f.prefix_expr_cast_expr(field.default_expr)
|
||||
@ -663,9 +655,7 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
|
||||
}
|
||||
f.write(strings.repeat(` `, max - field.name.len - comments_len))
|
||||
f.write(f.type_to_str(field.typ))
|
||||
if field.attrs.len > 0 {
|
||||
f.write(' [' + field.attrs.join(';') + ']')
|
||||
}
|
||||
f.inline_attrs(field.attrs)
|
||||
if field.has_default_expr {
|
||||
f.write(' = ')
|
||||
f.prefix_expr_cast_expr(field.default_expr)
|
||||
@ -1123,6 +1113,37 @@ pub fn (mut f Fmt) or_expr(or_block ast.OrExpr) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut f Fmt) attrs(attrs []table.Attr) {
|
||||
for attr in attrs {
|
||||
f.write('[')
|
||||
if attr.is_ctdefine {
|
||||
f.write('if ')
|
||||
}
|
||||
if attr.is_string {
|
||||
f.write("'")
|
||||
}
|
||||
f.write(attr.name)
|
||||
if attr.is_string {
|
||||
f.write("'")
|
||||
}
|
||||
f.writeln(']')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut f Fmt) inline_attrs(attrs []table.Attr) {
|
||||
if attrs.len == 0 {
|
||||
return
|
||||
}
|
||||
f.write(' [')
|
||||
for i, attr in attrs {
|
||||
if i > 0 {
|
||||
f.write(';')
|
||||
}
|
||||
f.write(attr.name)
|
||||
}
|
||||
f.write(']')
|
||||
}
|
||||
|
||||
enum CommentsLevel {
|
||||
keep
|
||||
indent
|
||||
@ -1181,6 +1202,7 @@ pub fn (mut f Fmt) comments(comments []ast.Comment, options CommentsOptions) {
|
||||
pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
||||
// println('$it.name find_comment($it.pos.line_nr)')
|
||||
// f.find_comment(it.pos.line_nr)
|
||||
f.attrs(node.attrs)
|
||||
f.write(node.stringify(f.table, f.cur_mod)) // `Expr` instead of `ast.Expr` in mod ast
|
||||
if node.language == .v {
|
||||
f.writeln(' {')
|
||||
|
5
vlib/v/fmt/tests/attrs_keep.vv
Normal file
5
vlib/v/fmt/tests/attrs_keep.vv
Normal file
@ -0,0 +1,5 @@
|
||||
[inline]
|
||||
[if debug]
|
||||
fn keep_attributes() {
|
||||
println('hi !')
|
||||
}
|
@ -83,7 +83,6 @@ mut:
|
||||
is_json_fn bool // inside json.encode()
|
||||
json_types []string // to avoid json gen duplicates
|
||||
pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name
|
||||
attrs []string // attributes before next decl stmt
|
||||
is_builtin_mod bool
|
||||
hotcode_fn_names []string
|
||||
// cur_fn ast.FnDecl
|
||||
@ -629,10 +628,6 @@ fn (mut g Gen) stmts(stmts []ast.Stmt) {
|
||||
if g.inside_ternary > 0 && i < stmts.len - 1 {
|
||||
g.write(',')
|
||||
}
|
||||
// clear attrs on next non Attr stmt
|
||||
if stmt !is ast.Attr {
|
||||
g.attrs = []
|
||||
}
|
||||
}
|
||||
g.indent--
|
||||
if g.inside_ternary > 0 {
|
||||
@ -674,10 +669,6 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
ast.AssignStmt {
|
||||
g.gen_assign_stmt(node)
|
||||
}
|
||||
ast.Attr {
|
||||
g.attrs << node.name
|
||||
g.writeln('// Attr: [$node.name]')
|
||||
}
|
||||
ast.Block {
|
||||
if node.is_unsafe {
|
||||
g.writeln('{ // Unsafe block')
|
||||
@ -868,6 +859,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
}
|
||||
ast.StructDecl {
|
||||
name := if node.language == .c { util.no_dots(node.name) } else { c_name(node.name) }
|
||||
// TODO For some reason, build fails with autofree with this line
|
||||
// as it's only informative, comment it for now
|
||||
// g.gen_attrs(node.attrs)
|
||||
// g.writeln('typedef struct {')
|
||||
// for field in it.fields {
|
||||
// field_type_sym := g.table.get_type_symbol(field.typ)
|
||||
@ -1070,6 +1064,12 @@ fn ctoslit(s string) string {
|
||||
return 'tos_lit("' + cestring(s) + '")'
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_attrs(attrs []table.Attr) {
|
||||
for attr in attrs {
|
||||
g.writeln('// Attr: [$attr.name]')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_assert_stmt(a ast.AssertStmt) {
|
||||
g.writeln('// assert')
|
||||
g.inside_ternary++
|
||||
|
@ -177,7 +177,7 @@ fn (mut g Gen) comp_for(node ast.CompFor) {
|
||||
} else {
|
||||
mut attrs := []string{}
|
||||
for attrib in method.attrs {
|
||||
attrs << 'tos_lit("$attrib")'
|
||||
attrs << 'tos_lit("$attrib.name")'
|
||||
}
|
||||
g.writeln('\t${node.val_var}.attrs = new_array_from_c_array($attrs.len, $attrs.len, sizeof(string), _MOV((string[$attrs.len]){' +
|
||||
attrs.join(', ') + '}));')
|
||||
@ -212,7 +212,7 @@ fn (mut g Gen) comp_for(node ast.CompFor) {
|
||||
} else {
|
||||
mut attrs := []string{}
|
||||
for attrib in field.attrs {
|
||||
attrs << 'tos_lit("$attrib")'
|
||||
attrs << 'tos_lit("$attrib.name")'
|
||||
}
|
||||
g.writeln('\t${node.val_var}.attrs = new_array_from_c_array($attrs.len, $attrs.len, sizeof(string), _MOV((string[$attrs.len]){' +
|
||||
attrs.join(', ') + '}));')
|
||||
|
@ -11,6 +11,9 @@ pub fn kek_cheburek() {
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
|
||||
// TODO For some reason, build fails with autofree with this line
|
||||
// as it's only informative, comment it for now
|
||||
// g.gen_attrs(it.attrs)
|
||||
if it.language == .c {
|
||||
// || it.no_body {
|
||||
return
|
||||
@ -33,9 +36,9 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
|
||||
}
|
||||
// g.cur_fn = it
|
||||
fn_start_pos := g.out.len
|
||||
msvc_attrs := g.write_fn_attrs()
|
||||
msvc_attrs := g.write_fn_attrs(it.attrs)
|
||||
// Live
|
||||
is_livefn := 'live' in g.attrs
|
||||
is_livefn := it.attrs.contains('live')
|
||||
is_livemain := g.pref.is_livemain && is_livefn
|
||||
is_liveshared := g.pref.is_liveshared && is_livefn
|
||||
is_livemode := g.pref.is_livemain || g.pref.is_liveshared
|
||||
@ -142,7 +145,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
|
||||
}
|
||||
// Profiling mode? Start counting at the beginning of the function (save current time).
|
||||
if g.pref.is_prof {
|
||||
g.profile_fn(it.name)
|
||||
g.profile_fn(it)
|
||||
}
|
||||
g.stmts(it.stmts)
|
||||
//
|
||||
@ -711,10 +714,10 @@ fn (g &Gen) fileis(s string) bool {
|
||||
return g.file.path.contains(s)
|
||||
}
|
||||
|
||||
fn (mut g Gen) write_fn_attrs() string {
|
||||
fn (mut g Gen) write_fn_attrs(attrs []table.Attr) string {
|
||||
mut msvc_attrs := ''
|
||||
for attr in g.attrs {
|
||||
match attr {
|
||||
for attr in attrs {
|
||||
match attr.name {
|
||||
'inline' {
|
||||
g.write('inline ')
|
||||
}
|
||||
|
@ -10,11 +10,13 @@ import v.depgraph
|
||||
const (
|
||||
// https://ecma-international.org/ecma-262/#sec-reserved-words
|
||||
js_reserved = ['await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger',
|
||||
'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'finally', 'for', 'function',
|
||||
'if', 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'package', 'private',
|
||||
'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof',
|
||||
'var', 'void', 'while', 'with', 'yield']
|
||||
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t']
|
||||
'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'finally', 'for', 'function', 'if',
|
||||
'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'package', 'private', 'protected',
|
||||
'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void',
|
||||
'while', 'with', 'yield']
|
||||
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t',
|
||||
'\t\t\t\t\t\t\t\t',
|
||||
]
|
||||
)
|
||||
|
||||
struct JsGen {
|
||||
@ -425,9 +427,6 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
||||
ast.AssignStmt {
|
||||
g.gen_assign_stmt(node)
|
||||
}
|
||||
ast.Attr {
|
||||
g.gen_attr(node)
|
||||
}
|
||||
ast.Block {
|
||||
g.gen_block(node)
|
||||
g.writeln('')
|
||||
@ -740,8 +739,10 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_attr(it ast.Attr) {
|
||||
g.writeln('/* [$it.name] */')
|
||||
fn (mut g JsGen) gen_attrs(attrs []table.Attr) {
|
||||
for attr in attrs {
|
||||
g.writeln('/* [$attr.name] */')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_block(it ast.Block) {
|
||||
@ -830,6 +831,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
||||
g.fn_decl = &it
|
||||
has_go := fn_has_go(it)
|
||||
is_main := it.name == 'main.main'
|
||||
g.gen_attrs(it.attrs)
|
||||
if is_main {
|
||||
// there is no concept of main in JS but we do have iife
|
||||
g.writeln('/* program entry point */')
|
||||
@ -1042,7 +1044,10 @@ fn (mut g JsGen) gen_hash_stmt(it ast.HashStmt) {
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
||||
if node.name.starts_with('JS.') { return }
|
||||
if node.name.starts_with('JS.') {
|
||||
return
|
||||
}
|
||||
g.gen_attrs(node.attrs)
|
||||
g.doc.gen_fac_fn(node.fields)
|
||||
g.write('function ${g.js_name(node.name)}({ ')
|
||||
for i, field in node.fields {
|
||||
|
@ -78,18 +78,18 @@ $enc_fn_dec {
|
||||
}
|
||||
info := sym.info as table.Struct
|
||||
for field in info.fields {
|
||||
if 'skip' in field.attrs {
|
||||
if field.attrs.contains('skip') {
|
||||
continue
|
||||
}
|
||||
mut name := field.name
|
||||
for attr in field.attrs {
|
||||
if attr.starts_with('json:') {
|
||||
name = attr[5..]
|
||||
if attr.name.starts_with('json:') {
|
||||
name = attr.name[5..]
|
||||
break
|
||||
}
|
||||
}
|
||||
field_type := g.typ(field.typ)
|
||||
if 'raw' in field.attrs {
|
||||
if field.attrs.contains('raw') {
|
||||
dec.writeln(' res . ${c_name(field.name)} = tos2(cJSON_PrintUnformatted(' + 'js_get(root, "$name")));')
|
||||
} else {
|
||||
// Now generate decoders for all field types in this struct
|
||||
|
@ -1,28 +1,35 @@
|
||||
module gen
|
||||
|
||||
pub struct ProfileCounterMeta{
|
||||
fn_name string
|
||||
vpc_name string
|
||||
import v.ast
|
||||
|
||||
pub struct ProfileCounterMeta {
|
||||
fn_name string
|
||||
vpc_name string
|
||||
vpc_calls string
|
||||
}
|
||||
|
||||
fn (mut g Gen) profile_fn(fn_name string){
|
||||
if g.pref.profile_no_inline && 'inline' in g.attrs {
|
||||
fn (mut g Gen) profile_fn(fn_decl ast.FnDecl) {
|
||||
if g.pref.profile_no_inline && fn_decl.attrs.contains('inline') {
|
||||
g.defer_profile_code = ''
|
||||
return
|
||||
}
|
||||
fn_name := fn_decl.name
|
||||
if fn_name.starts_with('time.vpc_now') {
|
||||
g.defer_profile_code = ''
|
||||
} else {
|
||||
measure_fn_name := if g.pref.os == .mac { 'time__vpc_now_darwin' } else { 'time__vpc_now' }
|
||||
fn_profile_counter_name := 'vpc_${g.last_fn_c_name}'
|
||||
fn_profile_counter_name := 'vpc_$g.last_fn_c_name'
|
||||
fn_profile_counter_name_calls := '${fn_profile_counter_name}_calls'
|
||||
g.writeln('')
|
||||
g.writeln('\tdouble _PROF_FN_START = ${measure_fn_name}(); ${fn_profile_counter_name_calls}++; // $fn_name')
|
||||
g.writeln('\tdouble _PROF_FN_START = ${measure_fn_name}(); $fn_profile_counter_name_calls++; // $fn_name')
|
||||
g.writeln('')
|
||||
g.defer_profile_code = '\t${fn_profile_counter_name} += ${measure_fn_name}() - _PROF_FN_START;'
|
||||
g.pcs_declarations.writeln('double ${fn_profile_counter_name} = 0.0; u64 ${fn_profile_counter_name_calls} = 0;')
|
||||
g.pcs << ProfileCounterMeta{ g.last_fn_c_name, fn_profile_counter_name, fn_profile_counter_name_calls }
|
||||
g.defer_profile_code = '\t$fn_profile_counter_name += ${measure_fn_name}() - _PROF_FN_START;'
|
||||
g.pcs_declarations.writeln('double $fn_profile_counter_name = 0.0; u64 $fn_profile_counter_name_calls = 0;')
|
||||
g.pcs << ProfileCounterMeta{
|
||||
fn_name: g.last_fn_c_name
|
||||
vpc_name: fn_profile_counter_name
|
||||
vpc_calls: fn_profile_counter_name_calls
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,13 +38,13 @@ pub fn (mut g Gen) gen_vprint_profile_stats() {
|
||||
fstring := '"%14lu %14.3fms %14.0fns %s \\n"'
|
||||
if g.pref.profile_file == '-' {
|
||||
for pc_meta in g.pcs {
|
||||
g.pcs_declarations.writeln('\tif (${pc_meta.vpc_calls}) printf($fstring, ${pc_meta.vpc_calls}, ${pc_meta.vpc_name}/1000000.0, ${pc_meta.vpc_name}/${pc_meta.vpc_calls}, "${pc_meta.fn_name}" );')
|
||||
g.pcs_declarations.writeln('\tif ($pc_meta.vpc_calls) printf($fstring, $pc_meta.vpc_calls, $pc_meta.vpc_name/1000000.0, $pc_meta.vpc_name/$pc_meta.vpc_calls, "$pc_meta.fn_name" );')
|
||||
}
|
||||
} else {
|
||||
g.pcs_declarations.writeln('\tFILE * fp;')
|
||||
g.pcs_declarations.writeln('\tfp = fopen ("${g.pref.profile_file}", "w+");')
|
||||
g.pcs_declarations.writeln('\tfp = fopen ("$g.pref.profile_file", "w+");')
|
||||
for pc_meta in g.pcs {
|
||||
g.pcs_declarations.writeln('\tif (${pc_meta.vpc_calls}) fprintf(fp, $fstring, ${pc_meta.vpc_calls}, ${pc_meta.vpc_name}/1000000.0, ${pc_meta.vpc_name}/${pc_meta.vpc_calls}, "${pc_meta.fn_name}" );')
|
||||
g.pcs_declarations.writeln('\tif ($pc_meta.vpc_calls) fprintf(fp, $fstring, $pc_meta.vpc_calls, $pc_meta.vpc_name/1000000.0, $pc_meta.vpc_name/$pc_meta.vpc_calls, "$pc_meta.fn_name" );')
|
||||
}
|
||||
g.pcs_declarations.writeln('\tfclose(fp);')
|
||||
}
|
||||
|
@ -131,8 +131,8 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
|
||||
fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
p.top_level_statement_start()
|
||||
start_pos := p.tok.position()
|
||||
is_deprecated := 'deprecated' in p.attrs
|
||||
mut is_unsafe := 'unsafe_fn' in p.attrs
|
||||
is_deprecated := p.attrs.contains('deprecated')
|
||||
mut is_unsafe := p.attrs.contains('unsafe_fn')
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
p.next()
|
||||
@ -141,7 +141,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
p.open_scope()
|
||||
// C. || JS.
|
||||
language := if p.tok.kind == .name && p.tok.lit == 'C' {
|
||||
is_unsafe = !('trusted_fn' in p.attrs)
|
||||
is_unsafe = !p.attrs.contains('trusted_fn')
|
||||
table.Language.c
|
||||
} else if p.tok.kind == .name && p.tok.lit == 'JS' {
|
||||
table.Language.js
|
||||
@ -244,12 +244,11 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
mut end_pos := p.prev_tok.position()
|
||||
// Return type
|
||||
mut return_type := table.void_type
|
||||
if p.tok.kind.is_start_of_type() || (p.tok.kind == .key_fn &&
|
||||
p.tok.line_nr == p.prev_tok.line_nr) {
|
||||
if p.tok.kind.is_start_of_type() ||
|
||||
(p.tok.kind == .key_fn && p.tok.line_nr == p.prev_tok.line_nr) {
|
||||
end_pos = p.tok.position()
|
||||
return_type = p.parse_type()
|
||||
}
|
||||
ctdefine := p.attr_ctdefine
|
||||
// Register
|
||||
if is_method {
|
||||
mut type_sym := p.table.get_type_symbol(rec_type)
|
||||
@ -263,7 +262,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
is_pub: is_pub
|
||||
is_deprecated: is_deprecated
|
||||
is_unsafe: is_unsafe
|
||||
ctdefine: ctdefine
|
||||
mod: p.mod
|
||||
attrs: p.attrs
|
||||
})
|
||||
@ -288,8 +286,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
is_pub: is_pub
|
||||
is_deprecated: is_deprecated
|
||||
is_unsafe: is_unsafe
|
||||
ctdefine: ctdefine
|
||||
mod: p.mod
|
||||
attrs: p.attrs
|
||||
language: language
|
||||
})
|
||||
}
|
||||
@ -328,7 +326,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
body_pos: body_start_pos
|
||||
file: p.file_name
|
||||
is_builtin: p.builtin_mod || p.mod in util.builtin_module_parts
|
||||
ctdefine: ctdefine
|
||||
attrs: p.attrs
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,8 +392,7 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool, bool) {
|
||||
// `int, int, string` (no names, just types)
|
||||
argname := if p.tok.kind == .name && p.tok.lit.len > 0 && p.tok.lit[0].is_capital() { p.prepend_mod(p.tok.lit) } else { p.tok.lit }
|
||||
types_only := p.tok.kind in [.amp, .ellipsis, .key_fn] ||
|
||||
(p.peek_tok.kind == .comma && p.table.known_type(argname)) ||
|
||||
p.peek_tok.kind == .rpar
|
||||
(p.peek_tok.kind == .comma && p.table.known_type(argname)) || p.peek_tok.kind == .rpar
|
||||
// TODO copy pasta, merge 2 branches
|
||||
if types_only {
|
||||
// p.warn('types only')
|
||||
|
@ -36,8 +36,7 @@ mut:
|
||||
pref &pref.Preferences
|
||||
builtin_mod bool // are we in the `builtin` module?
|
||||
mod string // current module name
|
||||
attrs []string // attributes before next decl stmt
|
||||
attr_ctdefine string
|
||||
attrs []table.Attr // attributes before next decl stmt
|
||||
expr_mod string // for constructing full type names in parse_type()
|
||||
scope &ast.Scope
|
||||
global_scope &ast.Scope
|
||||
@ -183,13 +182,9 @@ fn (mut p Parser) parse() ast.File {
|
||||
break
|
||||
}
|
||||
// println('stmt at ' + p.tok.str())
|
||||
stmt := p.top_stmt()
|
||||
// clear the attribtes at the end of next non Attr top level stmt
|
||||
if stmt !is ast.Attr {
|
||||
p.attrs = []
|
||||
p.attr_ctdefine = ''
|
||||
}
|
||||
stmts << stmt
|
||||
stmts << p.top_stmt()
|
||||
// clear the attributes after each statement
|
||||
p.attrs = []
|
||||
}
|
||||
// println('nr stmts = $stmts.len')
|
||||
// println(stmts[0])
|
||||
@ -408,96 +403,102 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
|
||||
tok_pos := p.tok.position()
|
||||
eprintln('parsing file: ${p.file_name:-30} | tok.kind: ${p.tok.kind:-10} | tok.lit: ${p.tok.lit:-10} | tok_pos: ${tok_pos.str():-45} | top_stmt')
|
||||
}
|
||||
match p.tok.kind {
|
||||
.key_pub {
|
||||
match p.peek_tok.kind {
|
||||
.key_const {
|
||||
return p.const_decl()
|
||||
for {
|
||||
match p.tok.kind {
|
||||
.key_pub {
|
||||
match p.peek_tok.kind {
|
||||
.key_const {
|
||||
return p.const_decl()
|
||||
}
|
||||
.key_fn {
|
||||
return p.fn_decl()
|
||||
}
|
||||
.key_struct, .key_union {
|
||||
return p.struct_decl()
|
||||
}
|
||||
.key_interface {
|
||||
return p.interface_decl()
|
||||
}
|
||||
.key_enum {
|
||||
return p.enum_decl()
|
||||
}
|
||||
.key_type {
|
||||
return p.type_decl()
|
||||
}
|
||||
else {
|
||||
p.error('wrong pub keyword usage')
|
||||
return ast.Stmt{}
|
||||
}
|
||||
}
|
||||
.key_fn {
|
||||
return p.fn_decl()
|
||||
}
|
||||
.key_struct, .key_union {
|
||||
return p.struct_decl()
|
||||
}
|
||||
.key_interface {
|
||||
return p.interface_decl()
|
||||
}
|
||||
.key_enum {
|
||||
return p.enum_decl()
|
||||
}
|
||||
.key_type {
|
||||
return p.type_decl()
|
||||
}
|
||||
else {
|
||||
p.error('wrong pub keyword usage')
|
||||
}
|
||||
.lsbr {
|
||||
// attrs are stores in `p.attrs()`
|
||||
p.attributes()
|
||||
continue
|
||||
}
|
||||
.key_interface {
|
||||
return p.interface_decl()
|
||||
}
|
||||
.key_import {
|
||||
p.error_with_pos('`import x` can only be declared at the beginning of the file',
|
||||
p.tok.position())
|
||||
return p.import_stmt()
|
||||
}
|
||||
.key_global {
|
||||
return p.global_decl()
|
||||
}
|
||||
.key_const {
|
||||
return p.const_decl()
|
||||
}
|
||||
.key_fn {
|
||||
return p.fn_decl()
|
||||
}
|
||||
.key_struct {
|
||||
return p.struct_decl()
|
||||
}
|
||||
.dollar {
|
||||
return p.comp_if()
|
||||
}
|
||||
.hash {
|
||||
return p.hash()
|
||||
}
|
||||
.key_type {
|
||||
return p.type_decl()
|
||||
}
|
||||
.key_enum {
|
||||
return p.enum_decl()
|
||||
}
|
||||
.key_union {
|
||||
return p.struct_decl()
|
||||
}
|
||||
.comment {
|
||||
return p.comment_stmt()
|
||||
}
|
||||
else {
|
||||
if p.pref.is_script && !p.pref.is_test {
|
||||
mut stmts := []ast.Stmt{}
|
||||
for p.tok.kind != .eof {
|
||||
stmts << p.stmt(false)
|
||||
}
|
||||
return ast.FnDecl{
|
||||
name: 'main.main'
|
||||
mod: 'main'
|
||||
stmts: stmts
|
||||
file: p.file_name
|
||||
return_type: table.void_type
|
||||
}
|
||||
} else if p.pref.is_fmt {
|
||||
return p.stmt(false)
|
||||
} else {
|
||||
p.error('bad top level statement ' + p.tok.str())
|
||||
return ast.Stmt{}
|
||||
}
|
||||
}
|
||||
}
|
||||
.lsbr {
|
||||
attrs := p.attributes(true)
|
||||
return attrs[0]
|
||||
}
|
||||
.key_interface {
|
||||
return p.interface_decl()
|
||||
}
|
||||
.key_import {
|
||||
p.error_with_pos('`import x` can only be declared at the beginning of the file',
|
||||
p.tok.position())
|
||||
return p.import_stmt()
|
||||
}
|
||||
.key_global {
|
||||
return p.global_decl()
|
||||
}
|
||||
.key_const {
|
||||
return p.const_decl()
|
||||
}
|
||||
.key_fn {
|
||||
return p.fn_decl()
|
||||
}
|
||||
.key_struct {
|
||||
return p.struct_decl()
|
||||
}
|
||||
.dollar {
|
||||
return p.comp_if()
|
||||
}
|
||||
.hash {
|
||||
return p.hash()
|
||||
}
|
||||
.key_type {
|
||||
return p.type_decl()
|
||||
}
|
||||
.key_enum {
|
||||
return p.enum_decl()
|
||||
}
|
||||
.key_union {
|
||||
return p.struct_decl()
|
||||
}
|
||||
.comment {
|
||||
return p.comment_stmt()
|
||||
}
|
||||
else {
|
||||
if p.pref.is_script && !p.pref.is_test {
|
||||
mut stmts := []ast.Stmt{}
|
||||
for p.tok.kind != .eof {
|
||||
stmts << p.stmt(false)
|
||||
}
|
||||
return ast.FnDecl{
|
||||
name: 'main.main'
|
||||
mod: 'main'
|
||||
stmts: stmts
|
||||
file: p.file_name
|
||||
return_type: table.void_type
|
||||
}
|
||||
} else if p.pref.is_fmt {
|
||||
return p.stmt(false)
|
||||
} else {
|
||||
p.error('bad top level statement ' + p.tok.str())
|
||||
return ast.Stmt{}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO remove dummy return statement
|
||||
// the compiler complains if it's not there
|
||||
return ast.Stmt{}
|
||||
}
|
||||
|
||||
// TODO [if vfmt]
|
||||
@ -691,40 +692,43 @@ fn (mut p Parser) expr_list() ([]ast.Expr, []ast.Comment) {
|
||||
}
|
||||
|
||||
// when is_top_stmt is true attrs are added to p.attrs
|
||||
fn (mut p Parser) attributes(is_top_stmt bool) []ast.Attr {
|
||||
mut attrs := []ast.Attr{}
|
||||
fn (mut p Parser) attributes() {
|
||||
p.check(.lsbr)
|
||||
mut has_ctdefine := false
|
||||
for p.tok.kind != .rsbr {
|
||||
start_pos := p.tok.position()
|
||||
attr := p.parse_attr()
|
||||
if attr in attrs || (is_top_stmt && attr.name in p.attrs) {
|
||||
if p.attrs.contains(attr.name) {
|
||||
p.error_with_pos('duplicate attribute `$attr.name`', start_pos.extend(p.prev_tok.position()))
|
||||
}
|
||||
if is_top_stmt {
|
||||
p.attrs << attr.name
|
||||
if attr.is_ctdefine {
|
||||
if has_ctdefine {
|
||||
p.error_with_pos('only one `[if flag]` may be applied at a time `$attr.name`',
|
||||
start_pos.extend(p.prev_tok.position()))
|
||||
} else {
|
||||
has_ctdefine = true
|
||||
}
|
||||
}
|
||||
attrs << attr
|
||||
p.attrs << attr
|
||||
if p.tok.kind != .semicolon {
|
||||
expected := `;`
|
||||
if p.tok.kind == .rsbr {
|
||||
p.next()
|
||||
break
|
||||
}
|
||||
p.error('unexpected `$p.tok.kind.str()`, expecting `$expected.str()`')
|
||||
p.error('unexpected `$p.tok.kind.str()`, expecting `;`')
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
if attrs.len == 0 {
|
||||
if p.attrs.len == 0 {
|
||||
p.error_with_pos('attributes cannot be empty', p.prev_tok.position().extend(p.tok.position()))
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
|
||||
fn (mut p Parser) parse_attr() ast.Attr {
|
||||
mut is_if_attr := false
|
||||
fn (mut p Parser) parse_attr() table.Attr {
|
||||
mut is_ctdefine := false
|
||||
if p.tok.kind == .key_if {
|
||||
p.next()
|
||||
is_if_attr = true
|
||||
is_ctdefine = true
|
||||
}
|
||||
mut name := ''
|
||||
is_string := p.tok.kind == .string
|
||||
@ -744,12 +748,10 @@ fn (mut p Parser) parse_attr() ast.Attr {
|
||||
}
|
||||
}
|
||||
}
|
||||
if is_if_attr {
|
||||
p.attr_ctdefine = name
|
||||
}
|
||||
return ast.Attr{
|
||||
return table.Attr{
|
||||
name: name
|
||||
is_string: is_string
|
||||
is_ctdefine: is_ctdefine
|
||||
}
|
||||
}
|
||||
|
||||
@ -1663,8 +1665,8 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
|
||||
}
|
||||
p.top_level_statement_end()
|
||||
p.check(.rcbr)
|
||||
is_flag := 'flag' in p.attrs
|
||||
is_multi_allowed := '_allow_multiple_values' in p.attrs
|
||||
is_flag := p.attrs.contains('flag')
|
||||
is_multi_allowed := p.attrs.contains('_allow_multiple_values')
|
||||
if is_flag {
|
||||
if fields.len > 32 {
|
||||
p.error('when an enum is used as bit field, it must have a max of 32 fields')
|
||||
|
@ -10,6 +10,8 @@ import v.util
|
||||
|
||||
fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||
p.top_level_statement_start()
|
||||
// save attributes, they will be changed later in fields
|
||||
attrs := p.attrs
|
||||
start_pos := p.tok.position()
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
@ -32,7 +34,6 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||
p.next() // C || JS
|
||||
p.next() // .
|
||||
}
|
||||
is_typedef := 'typedef' in p.attrs
|
||||
name_pos := p.tok.position()
|
||||
mut name := p.check_name()
|
||||
if name.len == 1 && name[0].is_capital() {
|
||||
@ -168,12 +169,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||
break
|
||||
}
|
||||
}
|
||||
mut attrs := []string{}
|
||||
if p.tok.kind == .lsbr {
|
||||
parsed_attrs := p.attributes(false)
|
||||
for attr in parsed_attrs {
|
||||
attrs << attr.name
|
||||
}
|
||||
// attrs are stored in `p.attrs`
|
||||
p.attributes()
|
||||
}
|
||||
mut default_expr := ast.Expr{}
|
||||
mut has_default_expr := false
|
||||
@ -198,7 +196,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||
comments: comments
|
||||
default_expr: default_expr
|
||||
has_default_expr: has_default_expr
|
||||
attrs: attrs
|
||||
attrs: p.attrs
|
||||
is_public: is_field_pub
|
||||
}
|
||||
fields << table.Field{
|
||||
@ -209,8 +207,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||
is_pub: is_field_pub
|
||||
is_mut: is_field_mut
|
||||
is_global: is_field_global
|
||||
attrs: attrs
|
||||
attrs: p.attrs
|
||||
}
|
||||
p.attrs = []
|
||||
// println('struct field $ti.name $field_name')
|
||||
}
|
||||
p.top_level_statement_end()
|
||||
@ -228,9 +227,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||
name: name
|
||||
info: table.Struct{
|
||||
fields: fields
|
||||
is_typedef: is_typedef
|
||||
is_typedef: attrs.contains('typedef')
|
||||
is_union: is_union
|
||||
is_ref_only: 'ref_only' in p.attrs
|
||||
is_ref_only: attrs.contains('ref_only')
|
||||
generic_types: generic_types
|
||||
}
|
||||
mod: p.mod
|
||||
@ -260,7 +259,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||
pub_mut_pos: pub_mut_pos
|
||||
language: language
|
||||
is_union: is_union
|
||||
attrs: p.attrs
|
||||
attrs: attrs
|
||||
end_comments: end_comments
|
||||
}
|
||||
}
|
||||
|
21
vlib/v/table/attr.v
Normal file
21
vlib/v/table/attr.v
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
module table
|
||||
|
||||
// e.g. `[unsafe_fn]`
|
||||
pub struct Attr {
|
||||
pub:
|
||||
name string
|
||||
is_string bool // `['xxx']`
|
||||
is_ctdefine bool // `[if flag]`
|
||||
}
|
||||
|
||||
pub fn (attrs []Attr) contains(str string) bool {
|
||||
for a in attrs {
|
||||
if a.name == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
@ -687,7 +687,7 @@ pub mut:
|
||||
default_expr FExpr
|
||||
has_default_expr bool
|
||||
default_val string
|
||||
attrs []string
|
||||
attrs []Attr
|
||||
is_pub bool
|
||||
is_mut bool
|
||||
is_global bool
|
||||
|
@ -33,7 +33,7 @@ pub:
|
||||
is_placeholder bool
|
||||
mod string
|
||||
ctdefine string // compile time define. myflag, when [if myflag] tag
|
||||
attrs []string
|
||||
attrs []Attr
|
||||
pub mut:
|
||||
name string
|
||||
}
|
||||
@ -527,7 +527,6 @@ pub fn (table &Table) sumtype_has_variant(parent, variant Type) bool {
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
pub fn (table &Table) known_type_names() []string {
|
||||
|
Loading…
Reference in New Issue
Block a user