all: make comment expressions + fix vfmt array init (#5851)
parent
39f90e25f3
commit
90d9040e6e
|
@ -9,11 +9,10 @@ const (
|
|||
'vlib/net/http/http_httpbin_test.v',
|
||||
]
|
||||
skip_on_musl = []string{}
|
||||
skip_on_ubuntu_musl =
|
||||
[
|
||||
skip_on_ubuntu_musl = [
|
||||
'vlib/net/http/cookie_test.v',
|
||||
'vlib/net/http/http_test.v',
|
||||
'vlib/net/websocket/ws_test.v'
|
||||
'vlib/net/websocket/ws_test.v',
|
||||
'vlib/sqlite/sqlite_test.v',
|
||||
'vlib/orm/orm_test.v',
|
||||
'vlib/clipboard/clipboard_test.v',
|
||||
|
@ -21,7 +20,7 @@ const (
|
|||
]
|
||||
skip_on_linux = []string{}
|
||||
skip_on_non_linux = [
|
||||
'vlib/net/websocket/ws_test.v'
|
||||
'vlib/net/websocket/ws_test.v',
|
||||
]
|
||||
skip_on_windows = [
|
||||
'vlib/orm/orm_test.v',
|
||||
|
@ -75,6 +74,6 @@ fn main() {
|
|||
tsession.test()
|
||||
eprintln(tsession.benchmark.total_message(title))
|
||||
if tsession.benchmark.nfail > 0 {
|
||||
panic('\nWARNING: failed ${tsession.benchmark.nfail} times.\n')
|
||||
panic('\nWARNING: failed $tsession.benchmark.nfail times.\n')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,15 +10,15 @@ import v.errors
|
|||
pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
|
||||
|
||||
pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | CastExpr |
|
||||
CharLiteral | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr |
|
||||
IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | MapInit | MatchExpr | None |
|
||||
OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr |
|
||||
StringInterLiteral | StringLiteral | StructInit | Type | TypeOf | UnsafeExpr
|
||||
CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr |
|
||||
IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | MapInit | MatchExpr |
|
||||
None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf |
|
||||
SqlExpr | StringInterLiteral | StringLiteral | StructInit | Type | TypeOf | UnsafeExpr
|
||||
|
||||
pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompFor |
|
||||
CompIf | ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt |
|
||||
ForStmt | GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl |
|
||||
Module | Return | SqlStmt | StructDecl | TypeDecl | UnsafeStmt
|
||||
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 | UnsafeStmt
|
||||
|
||||
pub type ScopeObject = ConstField | GlobalDecl | Var
|
||||
|
||||
|
@ -44,6 +44,7 @@ pub struct ExprStmt {
|
|||
pub:
|
||||
expr Expr
|
||||
pos token.Position
|
||||
comments []Comment
|
||||
is_expr bool
|
||||
pub mut:
|
||||
typ table.Type
|
||||
|
@ -284,6 +285,7 @@ pub struct Return {
|
|||
pub:
|
||||
pos token.Position
|
||||
exprs []Expr
|
||||
comments []Comment
|
||||
pub mut:
|
||||
types []table.Type
|
||||
}
|
||||
|
@ -579,6 +581,7 @@ pub:
|
|||
right []Expr
|
||||
op token.Kind
|
||||
pos token.Position
|
||||
comments []Comment
|
||||
pub mut:
|
||||
left []Expr
|
||||
left_types []table.Type
|
||||
|
@ -921,22 +924,25 @@ pub fn (expr Expr) position() token.Position {
|
|||
AsCast {
|
||||
return expr.pos
|
||||
}
|
||||
// ast.Ident { }
|
||||
CastExpr {
|
||||
return expr.pos
|
||||
}
|
||||
Assoc {
|
||||
return expr.pos
|
||||
}
|
||||
BoolLiteral {
|
||||
return expr.pos
|
||||
}
|
||||
// ast.Ident { }
|
||||
CallExpr {
|
||||
return expr.pos
|
||||
}
|
||||
CastExpr {
|
||||
return expr.pos
|
||||
}
|
||||
CharLiteral {
|
||||
return expr.pos
|
||||
}
|
||||
Comment {
|
||||
return expr.pos
|
||||
}
|
||||
EnumVal {
|
||||
return expr.pos
|
||||
}
|
||||
|
@ -1023,7 +1029,6 @@ pub fn (stmt Stmt) position() token.Position {
|
|||
// BranchStmt {
|
||||
// }
|
||||
*/
|
||||
Comment { return stmt.pos }
|
||||
CompIf { return stmt.pos }
|
||||
ConstDecl { return stmt.pos }
|
||||
/*
|
||||
|
|
|
@ -1865,10 +1865,10 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
node.pos)
|
||||
}
|
||||
}
|
||||
// ast.Attr {}
|
||||
ast.AssignStmt {
|
||||
c.assign_stmt(mut node)
|
||||
}
|
||||
ast.Attr {}
|
||||
ast.Block {
|
||||
c.stmts(node.stmts)
|
||||
}
|
||||
|
@ -2044,7 +2044,9 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
}
|
||||
}
|
||||
}
|
||||
// ast.HashStmt {}
|
||||
ast.GotoLabel {}
|
||||
ast.GotoStmt {}
|
||||
ast.HashStmt {}
|
||||
ast.Import {}
|
||||
ast.InterfaceDecl {
|
||||
c.interface_decl(node)
|
||||
|
@ -2074,10 +2076,6 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
c.stmts(node.stmts)
|
||||
c.inside_unsafe = false
|
||||
}
|
||||
else {
|
||||
// println('checker.stmt(): unhandled node')
|
||||
// println('checker.stmt(): unhandled node (${typeof(node)})')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2210,6 +2208,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
ast.CharLiteral {
|
||||
return table.byte_type
|
||||
}
|
||||
ast.Comment {
|
||||
return table.void_type
|
||||
}
|
||||
ast.ComptimeCall {
|
||||
node.sym = c.table.get_type_symbol(c.unwrap_generic(c.expr(node.left)))
|
||||
if node.is_vweb {
|
||||
|
|
|
@ -41,28 +41,22 @@ pub mut:
|
|||
attrs map[string]string
|
||||
}
|
||||
|
||||
pub fn merge_comments(stmts []ast.Stmt) string {
|
||||
pub fn merge_comments(comments []ast.Comment) string {
|
||||
mut res := []string{}
|
||||
for s in stmts {
|
||||
if s is ast.Comment {
|
||||
res << s.text.trim_left('|')
|
||||
}
|
||||
for comment in comments {
|
||||
res << comment.text.trim_left('|')
|
||||
}
|
||||
return res.join('\n')
|
||||
}
|
||||
|
||||
pub fn get_comment_block_right_before(stmts []ast.Stmt) string {
|
||||
if stmts.len == 0 {
|
||||
pub fn get_comment_block_right_before(comments []ast.Comment) string {
|
||||
if comments.len == 0 {
|
||||
return ''
|
||||
}
|
||||
mut comment := ''
|
||||
mut last_comment_line_nr := 0
|
||||
for i := stmts.len-1; i >= 0; i-- {
|
||||
stmt := stmts[i]
|
||||
if stmt !is ast.Comment {
|
||||
panic('Not a comment')
|
||||
}
|
||||
cmt := stmt as ast.Comment
|
||||
for i := comments.len - 1; i >= 0; i-- {
|
||||
cmt := comments[i]
|
||||
if last_comment_line_nr != 0 && cmt.pos.line_nr < last_comment_line_nr - 1 {
|
||||
// skip comments that are not part of a continuous block,
|
||||
// located right above the top level statement.
|
||||
|
@ -198,7 +192,9 @@ fn compare_nodes_by_category(a, b &DocNode) int {
|
|||
|
||||
pub fn (nodes []DocNode) index_by_name(node_name string) int {
|
||||
for i, node in nodes {
|
||||
if node.name != node_name { continue }
|
||||
if node.name != node_name {
|
||||
continue
|
||||
}
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
|
@ -208,7 +204,7 @@ pub fn (nodes []DocNode) find_children_of(parent string) []DocNode {
|
|||
return nodes.find_nodes_with_attr('parent', parent)
|
||||
}
|
||||
|
||||
pub fn (nodes []DocNode) find_nodes_with_attr(attr_name string, value string) []DocNode {
|
||||
pub fn (nodes []DocNode) find_nodes_with_attr(attr_name, value string) []DocNode {
|
||||
mut subgroup := []DocNode{}
|
||||
if attr_name.len == 0 {
|
||||
return subgroup
|
||||
|
@ -226,9 +222,13 @@ pub fn (nodes []DocNode) find_nodes_with_attr(attr_name string, value string) []
|
|||
fn get_parent_mod(dir string) ?string {
|
||||
$if windows {
|
||||
// windows root path is C: or D:
|
||||
if dir.len <= 2 { return error('root folder reached') }
|
||||
if dir.len <= 2 {
|
||||
return error('root folder reached')
|
||||
}
|
||||
} $else {
|
||||
if dir.len == 0 { return error('root folder reached') }
|
||||
if dir.len == 0 {
|
||||
return error('root folder reached')
|
||||
}
|
||||
}
|
||||
base_dir := os.base_dir(dir)
|
||||
if os.file_name(base_dir) in ['encoding', 'v'] && 'vlib' in base_dir {
|
||||
|
@ -249,7 +249,9 @@ fn get_parent_mod(dir string) ?string {
|
|||
return error('No V files found.')
|
||||
}
|
||||
tbl := table.new_table()
|
||||
scope := &ast.Scope{ parent: 0 }
|
||||
scope := &ast.Scope{
|
||||
parent: 0
|
||||
}
|
||||
file_ast := parser.parse_file(v_files[0], tbl, .skip_comments, prefs, scope)
|
||||
if file_ast.mod.name == 'main' {
|
||||
return ''
|
||||
|
@ -315,14 +317,16 @@ fn (mut d Doc) generate() ?Doc {
|
|||
last_import_stmt_idx = sidx
|
||||
}
|
||||
}
|
||||
mut prev_comments := []ast.Stmt{}
|
||||
mut prev_comments := []ast.Comment{}
|
||||
mut imports_section := true
|
||||
for sidx, stmt in stmts {
|
||||
// eprintln('stmt typeof: ' + typeof(stmt))
|
||||
if stmt is ast.Comment {
|
||||
prev_comments << stmt
|
||||
if stmt is ast.ExprStmt {
|
||||
if stmt.expr is ast.Comment as cmt {
|
||||
prev_comments << cmt
|
||||
continue
|
||||
}
|
||||
}
|
||||
// TODO: Fetch head comment once
|
||||
if stmt is ast.Module {
|
||||
// the previous comments were probably a copyright/license one
|
||||
|
@ -385,7 +389,9 @@ fn (mut d Doc) generate() ?Doc {
|
|||
name: node.attrs['parent']
|
||||
content: ''
|
||||
comment: ''
|
||||
attrs: {'category': 'Structs'}
|
||||
attrs: {
|
||||
'category': 'Structs'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -420,7 +426,6 @@ fn (mut d Doc) generate() ?Doc {
|
|||
}
|
||||
prev_comments = []
|
||||
}
|
||||
|
||||
d.fmt.mod2alias = map[string]string{}
|
||||
}
|
||||
d.time_generated = time.now()
|
||||
|
|
|
@ -17,11 +17,6 @@ const (
|
|||
max_len = [0, 35, 85, 93, 100]
|
||||
)
|
||||
|
||||
enum CommentsLevel {
|
||||
keep
|
||||
indent
|
||||
}
|
||||
|
||||
pub struct Fmt {
|
||||
pub mut:
|
||||
table &table.Table
|
||||
|
@ -251,6 +246,9 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
|
|||
}
|
||||
match node {
|
||||
ast.AssignStmt {
|
||||
f.comments(node.comments, {
|
||||
inline: false
|
||||
})
|
||||
for i, left in node.left {
|
||||
if left is ast.Ident {
|
||||
var_info := left.var_info()
|
||||
|
@ -302,9 +300,6 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
|
|||
else {}
|
||||
}
|
||||
}
|
||||
ast.Comment {
|
||||
f.comment(it)
|
||||
}
|
||||
ast.CompFor {}
|
||||
ast.CompIf {
|
||||
inversion := if it.is_not { '!' } else { '' }
|
||||
|
@ -331,19 +326,27 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
|
|||
}
|
||||
name := it.name.after('.')
|
||||
f.writeln('enum $name {')
|
||||
f.comments(it.comments, false, .indent)
|
||||
f.comments(it.comments, {
|
||||
level: .indent
|
||||
})
|
||||
for field in it.fields {
|
||||
f.write('\t$field.name')
|
||||
if field.has_expr {
|
||||
f.write(' = ')
|
||||
f.expr(field.expr)
|
||||
}
|
||||
f.comments(field.comments, true, .indent)
|
||||
f.comments(field.comments, {
|
||||
has_nl: false
|
||||
level: .indent
|
||||
})
|
||||
f.writeln('')
|
||||
}
|
||||
f.writeln('}\n')
|
||||
}
|
||||
ast.ExprStmt {
|
||||
f.comments(it.comments, {
|
||||
inline: false
|
||||
})
|
||||
f.expr(it.expr)
|
||||
if !f.single_line_if {
|
||||
f.writeln('')
|
||||
|
@ -434,6 +437,9 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
|
|||
f.mod(it)
|
||||
}
|
||||
ast.Return {
|
||||
f.comments(it.comments, {
|
||||
inline: false
|
||||
})
|
||||
f.write('return')
|
||||
if it.exprs.len > 1 {
|
||||
// multiple returns
|
||||
|
@ -618,7 +624,8 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
|
|||
for j < comments.len && comments[j].pos.pos < field.pos.pos {
|
||||
f.indent++
|
||||
f.empty_line = true
|
||||
f.comment(comments[j])
|
||||
f.comment(comments[j], {})
|
||||
f.writeln('')
|
||||
f.indent--
|
||||
j++
|
||||
}
|
||||
|
@ -651,7 +658,8 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
|
|||
for comment in node.end_comments {
|
||||
f.indent++
|
||||
f.empty_line = true
|
||||
f.comment(comment)
|
||||
f.comment(comment, {})
|
||||
f.writeln('')
|
||||
f.indent--
|
||||
}
|
||||
f.writeln('}\n')
|
||||
|
@ -765,6 +773,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
|||
ast.CharLiteral {
|
||||
f.write('`$node.val`')
|
||||
}
|
||||
ast.Comment {
|
||||
f.comment(node, {})
|
||||
}
|
||||
ast.ComptimeCall {
|
||||
if node.is_vweb {
|
||||
f.write('$' + 'vweb.html()')
|
||||
|
@ -1120,10 +1131,21 @@ pub fn (mut f Fmt) or_expr(or_block ast.OrExpr) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) comment(node ast.Comment) {
|
||||
enum CommentsLevel {
|
||||
keep
|
||||
indent
|
||||
}
|
||||
|
||||
struct CommentsOptions {
|
||||
has_nl bool = true
|
||||
inline bool = true
|
||||
level CommentsLevel = .keep
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) comment(node ast.Comment, options CommentsOptions) {
|
||||
if !node.text.contains('\n') {
|
||||
is_separate_line := node.text.starts_with('|')
|
||||
mut s := if is_separate_line { node.text[1..] } else { node.text }
|
||||
is_separate_line := !options.inline || node.text.starts_with('|')
|
||||
mut s := if node.text.starts_with('|') { node.text[1..] } else { node.text }
|
||||
if s == '' {
|
||||
s = '//'
|
||||
} else {
|
||||
|
@ -1133,7 +1155,7 @@ pub fn (mut f Fmt) comment(node ast.Comment) {
|
|||
f.remove_new_line() // delete the generated \n
|
||||
f.write(' ')
|
||||
}
|
||||
f.writeln(s)
|
||||
f.write(s)
|
||||
return
|
||||
}
|
||||
lines := node.text.split_into_lines()
|
||||
|
@ -1143,25 +1165,25 @@ pub fn (mut f Fmt) comment(node ast.Comment) {
|
|||
f.empty_line = false
|
||||
}
|
||||
f.empty_line = true
|
||||
f.writeln('*/')
|
||||
f.write('*/')
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) comments(some_comments []ast.Comment, remove_last_new_line bool, level CommentsLevel) {
|
||||
for c in some_comments {
|
||||
pub fn (mut f Fmt) comments(comments []ast.Comment, options CommentsOptions) {
|
||||
for i, c in comments {
|
||||
if !f.out.last_n(1)[0].is_space() {
|
||||
f.write('\t')
|
||||
}
|
||||
if level == .indent {
|
||||
if options.level == .indent {
|
||||
f.indent++
|
||||
}
|
||||
f.comment(c)
|
||||
if level == .indent {
|
||||
f.comment(c, options)
|
||||
if i < comments.len - 1 || options.has_nl {
|
||||
f.writeln('')
|
||||
}
|
||||
if options.level == .indent {
|
||||
f.indent--
|
||||
}
|
||||
}
|
||||
if remove_last_new_line {
|
||||
f.remove_new_line()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
||||
|
@ -1232,7 +1254,7 @@ pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
|
|||
f.single_line_if = single_line
|
||||
for i, branch in it.branches {
|
||||
if branch.comments.len > 0 {
|
||||
f.comments(branch.comments, true, .keep)
|
||||
f.comments(branch.comments, {})
|
||||
}
|
||||
if i == 0 {
|
||||
f.write('if ')
|
||||
|
@ -1373,7 +1395,8 @@ pub fn (mut f Fmt) match_expr(it ast.MatchExpr) {
|
|||
}
|
||||
for branch in it.branches {
|
||||
if branch.comment.text != '' {
|
||||
f.comment(branch.comment)
|
||||
f.comment(branch.comment, {})
|
||||
f.writeln('')
|
||||
}
|
||||
if !branch.is_else {
|
||||
// normal branch
|
||||
|
@ -1404,7 +1427,7 @@ pub fn (mut f Fmt) match_expr(it ast.MatchExpr) {
|
|||
}
|
||||
}
|
||||
if branch.post_comments.len > 0 {
|
||||
f.comments(branch.post_comments, false, .keep)
|
||||
f.comments(branch.post_comments, {})
|
||||
}
|
||||
}
|
||||
f.indent--
|
||||
|
@ -1456,6 +1479,7 @@ fn (mut f Fmt) write_language_prefix(lang table.Language) {
|
|||
fn expr_is_single_line(expr ast.Expr) bool {
|
||||
match expr {
|
||||
ast.IfExpr { return false }
|
||||
ast.Comment { return false }
|
||||
else {}
|
||||
}
|
||||
return true
|
||||
|
@ -1553,9 +1577,12 @@ pub fn (mut f Fmt) array_init(it ast.ArrayInit) {
|
|||
f.expr(expr)
|
||||
if i == it.exprs.len - 1 {
|
||||
if is_new_line {
|
||||
if expr !is ast.Comment {
|
||||
f.write(',')
|
||||
}
|
||||
f.writeln('')
|
||||
}
|
||||
} else {
|
||||
} else if expr !is ast.Comment {
|
||||
f.write(',')
|
||||
}
|
||||
last_line_nr = line_nr
|
||||
|
@ -1634,7 +1661,8 @@ pub fn (mut f Fmt) const_decl(it ast.ConstDecl) {
|
|||
comments := field.comments
|
||||
mut j := 0
|
||||
for j < comments.len && comments[j].pos.pos < field.pos.pos {
|
||||
f.comment(comments[j])
|
||||
f.comment(comments[j], {})
|
||||
f.writeln('')
|
||||
j++
|
||||
}
|
||||
name := field.name.after('.')
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
fn main() {
|
||||
arr := [
|
||||
// test 0
|
||||
1,
|
||||
// test 1
|
||||
2,
|
||||
// test 2
|
||||
]
|
||||
}
|
|
@ -7,7 +7,7 @@ fn main() {
|
|||
expected_flags := [
|
||||
make_flag('solaris', '-L', '/opt/local/lib'),
|
||||
make_flag('darwin', '-framework', 'Cocoa'),
|
||||
make_flag('windows', '-l', 'gdi32')
|
||||
make_flag('windows', '-l', 'gdi32'),
|
||||
]
|
||||
x := []int{len: 10, cap: 100, init: 1}
|
||||
_ := expected_flags
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
fn fun() int {
|
||||
// comment zero
|
||||
return 0
|
||||
}
|
||||
|
||||
fn mr_fun() (int, int) {
|
||||
// one comment
|
||||
// another comment
|
||||
return 1, 2
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// this is a comment
|
||||
a := 1
|
||||
// and another comment
|
||||
// just to make it worse
|
||||
b, c := a, 2
|
||||
d := c // and an extra one
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fn fun() int {
|
||||
return /* comment zero */ 0
|
||||
}
|
||||
|
||||
fn mr_fun() (int, int) {
|
||||
return /* one comment */ 1, /* another comment */ 2
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := /* this is a comment */ 1
|
||||
b, c := /* and another comment */ a, /* just to make it worse */ 2
|
||||
d := c // and an extra one
|
||||
}
|
|
@ -17,13 +17,13 @@ const (
|
|||
'first line',
|
||||
'second line',
|
||||
'third line',
|
||||
'fourth line'
|
||||
'fourth line',
|
||||
]
|
||||
)
|
||||
|
||||
const (
|
||||
i_am_a_very_long_constant_name_so_i_stand_alone_and_my_length_is_over_90_characters = [
|
||||
'testforit'
|
||||
'testforit',
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -34,27 +34,27 @@ pub const (
|
|||
fn main() {
|
||||
a := [
|
||||
[3, 5, 6],
|
||||
[7, 9, 2]
|
||||
[7, 9, 2],
|
||||
]
|
||||
b := [[
|
||||
[2, 5, 8],
|
||||
[5, 1, 3],
|
||||
[2, 6, 0]
|
||||
[2, 6, 0],
|
||||
], [
|
||||
[9, 4, 5],
|
||||
[7, 2, 3],
|
||||
[1, 2, 3]
|
||||
[1, 2, 3],
|
||||
]]
|
||||
c := [
|
||||
[
|
||||
[2, 5, 8],
|
||||
[5, 1, 3],
|
||||
[2, 6, 0]
|
||||
[2, 6, 0],
|
||||
],
|
||||
[
|
||||
[9, 4, 5],
|
||||
[7, 2, 3],
|
||||
[1, 2, 3]
|
||||
]
|
||||
[1, 2, 3],
|
||||
],
|
||||
]
|
||||
}
|
||||
|
|
|
@ -676,7 +676,6 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
g.const_decl(node)
|
||||
// }
|
||||
}
|
||||
ast.Comment {}
|
||||
ast.CompFor {
|
||||
g.comp_for(node)
|
||||
}
|
||||
|
@ -1679,6 +1678,7 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
ast.ComptimeCall {
|
||||
g.comptime_call(node)
|
||||
}
|
||||
ast.Comment {}
|
||||
ast.ConcatExpr {
|
||||
g.concat_expr(node)
|
||||
}
|
||||
|
|
|
@ -62,9 +62,7 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
g.enable_doc = false
|
||||
}
|
||||
g.init()
|
||||
|
||||
mut graph := depgraph.new_dep_graph()
|
||||
|
||||
// Get class methods
|
||||
for file in files {
|
||||
g.file = file
|
||||
|
@ -73,27 +71,22 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
g.find_class_methods(file.stmts)
|
||||
g.escape_namespace()
|
||||
}
|
||||
|
||||
for file in files {
|
||||
g.file = file
|
||||
g.enter_namespace(g.file.mod.name)
|
||||
g.is_test = g.file.path.ends_with('_test.v')
|
||||
|
||||
// store imports
|
||||
mut imports := []string{}
|
||||
for imp in g.file.imports {
|
||||
imports << imp.mod
|
||||
}
|
||||
graph.add(g.file.mod.name, imports)
|
||||
|
||||
g.stmts(file.stmts)
|
||||
// store the current namespace
|
||||
g.escape_namespace()
|
||||
}
|
||||
|
||||
// resolve imports
|
||||
deps_resolved := graph.resolve()
|
||||
|
||||
mut out := g.hashes() + g.definitions.str()
|
||||
for node in deps_resolved.nodes {
|
||||
name := g.js_name(node.name).replace('.', '_')
|
||||
|
@ -103,7 +96,9 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
out += 'const $name = (function ('
|
||||
imports := g.namespace_imports[node.name]
|
||||
for i, key in imports.keys() {
|
||||
if i > 0 { out += ', ' }
|
||||
if i > 0 {
|
||||
out += ', '
|
||||
}
|
||||
out += imports[key]
|
||||
}
|
||||
out += ') {\n\t'
|
||||
|
@ -117,13 +112,19 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
out += '\n\treturn {'
|
||||
for i, pub_var in g.namespaces_pub[node.name] {
|
||||
out += '\n\t\t$pub_var'
|
||||
if i < g.namespaces_pub[node.name].len - 1 { out += ',' }
|
||||
if i < g.namespaces_pub[node.name].len - 1 {
|
||||
out += ','
|
||||
}
|
||||
}
|
||||
if g.namespaces_pub[node.name].len > 0 {
|
||||
out += '\n\t'
|
||||
}
|
||||
if g.namespaces_pub[node.name].len > 0 { out += '\n\t' }
|
||||
out += '};'
|
||||
out += '\n})('
|
||||
for i, key in imports.keys() {
|
||||
if i > 0 { out += ', ' }
|
||||
if i > 0 {
|
||||
out += ', '
|
||||
}
|
||||
out += key.replace('.', '_')
|
||||
}
|
||||
out += ');\n\n'
|
||||
|
@ -157,9 +158,9 @@ pub fn (mut g JsGen) find_class_methods(stmts []ast.Stmt) {
|
|||
for stmt in stmts {
|
||||
match stmt {
|
||||
ast.FnDecl {
|
||||
if it.is_method {
|
||||
if stmt.is_method {
|
||||
// Found struct method, store it to be generated along with the class.
|
||||
class_name := g.table.get_type_name(it.receiver.typ)
|
||||
class_name := g.table.get_type_name(stmt.receiver.typ)
|
||||
// Workaround until `map[key] << val` works.
|
||||
mut arr := g.method_fn_decls[class_name]
|
||||
arr << stmt
|
||||
|
@ -178,7 +179,7 @@ pub fn (mut g JsGen) init() {
|
|||
}
|
||||
|
||||
pub fn (g JsGen) hashes() string {
|
||||
mut res := '// V_COMMIT_HASH ${util.vhash()}\n'
|
||||
mut res := '// V_COMMIT_HASH $util.vhash()\n'
|
||||
res += '// V_CURRENT_COMMIT_HASH ${util.githash(g.pref.building_v)}\n'
|
||||
return res
|
||||
}
|
||||
|
@ -187,7 +188,6 @@ pub fn (g JsGen) hashes() string {
|
|||
pub fn (mut g JsGen) typ(t table.Type) string {
|
||||
sym := g.table.get_type_symbol(t)
|
||||
mut styp := ''
|
||||
|
||||
match sym.kind {
|
||||
.placeholder {
|
||||
// This should never happen: means checker bug
|
||||
|
@ -282,10 +282,11 @@ fn (mut g JsGen) fn_typ(args []table.Arg, return_type table.Type) string {
|
|||
mut res := '('
|
||||
for i, arg in args {
|
||||
res += '$arg.name: ${g.typ(arg.typ)}'
|
||||
if i < args.len - 1 { res += ', ' }
|
||||
if i < args.len - 1 {
|
||||
res += ', '
|
||||
}
|
||||
}
|
||||
return res + ') => ' + g.typ(return_type)
|
||||
|
||||
}
|
||||
|
||||
fn (mut g JsGen) struct_typ(s string) string {
|
||||
|
@ -293,17 +294,21 @@ fn (mut g JsGen) struct_typ(s string) string {
|
|||
mut name := if ns == g.namespace { s.split('.').last() } else { g.get_alias(s) }
|
||||
mut styp := ''
|
||||
for i, v in name.split('.') {
|
||||
if i == 0 { styp = v }
|
||||
else { styp += '["$v"]' }
|
||||
if i == 0 {
|
||||
styp = v
|
||||
} else {
|
||||
styp += '["$v"]'
|
||||
}
|
||||
}
|
||||
if ns in ['', g.namespace] {
|
||||
return styp
|
||||
}
|
||||
if ns in ['', g.namespace] { return styp }
|
||||
return styp + '["prototype"]'
|
||||
}
|
||||
|
||||
fn (mut g JsGen) to_js_typ_val(t table.Type) string {
|
||||
sym := g.table.get_type_symbol(t)
|
||||
mut styp := ''
|
||||
|
||||
match sym.kind {
|
||||
.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64, .f32, .f64, .any_int, .any_float, .size_t {
|
||||
styp = '0'
|
||||
|
@ -366,18 +371,22 @@ pub fn (mut g JsGen) new_tmp_var() string {
|
|||
// 'fn' => ''
|
||||
[inline]
|
||||
fn get_ns(s string) string {
|
||||
idx := s.last_index('.') or { return '' }
|
||||
idx := s.last_index('.') or {
|
||||
return ''
|
||||
}
|
||||
return s.substr(0, idx)
|
||||
}
|
||||
|
||||
fn (mut g JsGen) get_alias(name string) string {
|
||||
ns := get_ns(name)
|
||||
if ns == '' { return name }
|
||||
|
||||
if ns == '' {
|
||||
return name
|
||||
}
|
||||
imports := g.namespace_imports[g.namespace]
|
||||
alias := imports[ns]
|
||||
if alias == '' { return name }
|
||||
|
||||
if alias == '' {
|
||||
return name
|
||||
}
|
||||
return alias + '.' + name.split('.').last()
|
||||
}
|
||||
|
||||
|
@ -386,7 +395,9 @@ fn (mut g JsGen) js_name(name_ string) string {
|
|||
mut name := if ns == g.namespace { name_.split('.').last() } else { g.get_alias(name_) }
|
||||
mut parts := name.split('.')
|
||||
for i, p in parts {
|
||||
if p in js_reserved { parts[i] = 'v_$p' }
|
||||
if p in js_reserved {
|
||||
parts[i] = 'v_$p'
|
||||
}
|
||||
}
|
||||
return parts.join('.')
|
||||
}
|
||||
|
@ -401,82 +412,77 @@ fn (mut g JsGen) stmts(stmts []ast.Stmt) {
|
|||
|
||||
fn (mut g JsGen) stmt(node ast.Stmt) {
|
||||
g.stmt_start_pos = g.out.len
|
||||
|
||||
match node {
|
||||
ast.AssertStmt {
|
||||
g.gen_assert_stmt(it)
|
||||
g.gen_assert_stmt(node)
|
||||
}
|
||||
ast.AssignStmt {
|
||||
g.gen_assign_stmt(it)
|
||||
g.gen_assign_stmt(node)
|
||||
}
|
||||
ast.Attr {
|
||||
g.gen_attr(it)
|
||||
g.gen_attr(node)
|
||||
}
|
||||
ast.Block {
|
||||
g.gen_block(it)
|
||||
g.gen_block(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.BranchStmt {
|
||||
g.gen_branch_stmt(it)
|
||||
}
|
||||
ast.Comment {
|
||||
// Skip: don't generate comments
|
||||
}
|
||||
ast.CompFor {
|
||||
g.gen_branch_stmt(node)
|
||||
}
|
||||
ast.CompFor {}
|
||||
ast.CompIf {
|
||||
// skip: JS has no compile time if
|
||||
}
|
||||
ast.ConstDecl {
|
||||
g.gen_const_decl(it)
|
||||
g.gen_const_decl(node)
|
||||
}
|
||||
ast.DeferStmt {
|
||||
g.defer_stmts << *it
|
||||
g.defer_stmts << *node
|
||||
}
|
||||
ast.EnumDecl {
|
||||
g.gen_enum_decl(it)
|
||||
g.gen_enum_decl(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.ExprStmt {
|
||||
g.gen_expr_stmt(it)
|
||||
g.gen_expr_stmt(node)
|
||||
}
|
||||
ast.FnDecl {
|
||||
g.fn_decl = it
|
||||
g.gen_fn_decl(it)
|
||||
g.fn_decl = node
|
||||
g.gen_fn_decl(node)
|
||||
}
|
||||
ast.ForCStmt {
|
||||
g.gen_for_c_stmt(it)
|
||||
g.gen_for_c_stmt(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.ForInStmt {
|
||||
g.gen_for_in_stmt(it)
|
||||
g.gen_for_in_stmt(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.ForStmt {
|
||||
g.gen_for_stmt(it)
|
||||
g.gen_for_stmt(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.GlobalDecl {
|
||||
// TODO
|
||||
}
|
||||
ast.GoStmt {
|
||||
g.gen_go_stmt(it)
|
||||
g.gen_go_stmt(node)
|
||||
g.writeln('')
|
||||
}
|
||||
ast.GotoLabel {
|
||||
g.writeln('${g.js_name(it.name)}:')
|
||||
g.writeln('${g.js_name(node.name)}:')
|
||||
}
|
||||
ast.GotoStmt {
|
||||
// skip: JS has no goto
|
||||
}
|
||||
ast.HashStmt {
|
||||
g.gen_hash_stmt(it)
|
||||
g.gen_hash_stmt(node)
|
||||
}
|
||||
ast.Import {
|
||||
g.gen_import_stmt(it)
|
||||
g.gen_import_stmt(node)
|
||||
}
|
||||
ast.InterfaceDecl {
|
||||
g.gen_interface_decl(it)
|
||||
g.gen_interface_decl(node)
|
||||
}
|
||||
ast.Module {
|
||||
// skip: namespacing implemented externally
|
||||
|
@ -485,18 +491,17 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
if g.defer_stmts.len > 0 {
|
||||
g.gen_defer_stmts()
|
||||
}
|
||||
g.gen_return_stmt(it)
|
||||
}
|
||||
ast.SqlStmt{
|
||||
g.gen_return_stmt(node)
|
||||
}
|
||||
ast.SqlStmt {}
|
||||
ast.StructDecl {
|
||||
g.gen_struct_decl(it)
|
||||
g.gen_struct_decl(node)
|
||||
}
|
||||
ast.TypeDecl {
|
||||
// skip JS has no typedecl
|
||||
}
|
||||
ast.UnsafeStmt {
|
||||
g.stmts(it.stmts)
|
||||
g.stmts(node.stmts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -504,10 +509,10 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
fn (mut g JsGen) expr(node ast.Expr) {
|
||||
match node {
|
||||
ast.AnonFn {
|
||||
g.gen_fn_decl(it.decl)
|
||||
g.gen_fn_decl(node.decl)
|
||||
}
|
||||
ast.ArrayInit {
|
||||
g.gen_array_init_expr(it)
|
||||
g.gen_array_init_expr(node)
|
||||
}
|
||||
ast.AsCast {
|
||||
// skip: JS has no types, so no need to cast
|
||||
|
@ -517,57 +522,58 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
// TODO
|
||||
}
|
||||
ast.BoolLiteral {
|
||||
if it.val == true {
|
||||
if node.val == true {
|
||||
g.write('true')
|
||||
} else {
|
||||
g.write('false')
|
||||
}
|
||||
}
|
||||
ast.CallExpr {
|
||||
g.gen_call_expr(it)
|
||||
g.gen_call_expr(node)
|
||||
}
|
||||
ast.CastExpr {
|
||||
// JS has no types, so no need to cast
|
||||
// Just write the expression inside
|
||||
g.expr(it.expr)
|
||||
g.expr(node.expr)
|
||||
}
|
||||
ast.CharLiteral {
|
||||
g.write("'$it.val'")
|
||||
g.write("'$node.val'")
|
||||
}
|
||||
ast.Comment {}
|
||||
ast.ConcatExpr {
|
||||
// TODO
|
||||
}
|
||||
ast.EnumVal {
|
||||
sym := g.table.get_type_symbol(it.typ)
|
||||
sym := g.table.get_type_symbol(node.typ)
|
||||
styp := g.js_name(sym.name)
|
||||
g.write('${styp}.${it.val}')
|
||||
g.write('${styp}.$node.val')
|
||||
}
|
||||
ast.FloatLiteral {
|
||||
g.write(it.val)
|
||||
g.write(node.val)
|
||||
}
|
||||
ast.Ident {
|
||||
g.gen_ident(it)
|
||||
g.gen_ident(node)
|
||||
}
|
||||
ast.IfExpr {
|
||||
g.gen_if_expr(it)
|
||||
g.gen_if_expr(node)
|
||||
}
|
||||
ast.IfGuardExpr {
|
||||
// TODO no optionals yet
|
||||
}
|
||||
ast.IndexExpr {
|
||||
g.gen_index_expr(it)
|
||||
g.gen_index_expr(node)
|
||||
}
|
||||
ast.InfixExpr {
|
||||
g.gen_infix_expr(it)
|
||||
g.gen_infix_expr(node)
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.write(it.val)
|
||||
g.write(node.val)
|
||||
}
|
||||
ast.LockExpr {
|
||||
g.gen_lock_expr(it)
|
||||
g.gen_lock_expr(node)
|
||||
}
|
||||
ast.MapInit {
|
||||
g.gen_map_init_expr(it)
|
||||
g.gen_map_init_expr(node)
|
||||
}
|
||||
ast.MatchExpr {
|
||||
// TODO
|
||||
|
@ -580,26 +586,26 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
}
|
||||
ast.ParExpr {
|
||||
g.write('(')
|
||||
g.expr(it.expr)
|
||||
g.expr(node.expr)
|
||||
g.write(')')
|
||||
}
|
||||
ast.PostfixExpr {
|
||||
g.expr(it.expr)
|
||||
g.write(it.op.str())
|
||||
g.expr(node.expr)
|
||||
g.write(node.op.str())
|
||||
}
|
||||
ast.PrefixExpr {
|
||||
if it.op in [.amp, .mul] {
|
||||
if node.op in [.amp, .mul] {
|
||||
// C pointers/references: ignore them
|
||||
} else {
|
||||
g.write(it.op.str())
|
||||
g.write(node.op.str())
|
||||
}
|
||||
g.expr(it.right)
|
||||
g.expr(node.right)
|
||||
}
|
||||
ast.RangeExpr {
|
||||
// Only used in IndexExpr, requires index type info
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
g.gen_selector_expr(it)
|
||||
g.gen_selector_expr(node)
|
||||
}
|
||||
ast.SizeOf {
|
||||
// TODO
|
||||
|
@ -608,14 +614,14 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
// TODO
|
||||
}
|
||||
ast.StringInterLiteral {
|
||||
g.gen_string_inter_literal(it)
|
||||
g.gen_string_inter_literal(node)
|
||||
}
|
||||
ast.StringLiteral {
|
||||
g.write('"$it.val"')
|
||||
g.write('"$node.val"')
|
||||
}
|
||||
ast.StructInit {
|
||||
// `user := User{name: 'Bob'}`
|
||||
g.gen_struct_init(it)
|
||||
g.gen_struct_init(node)
|
||||
}
|
||||
ast.Type {
|
||||
// skip: JS has no types
|
||||
|
@ -623,24 +629,23 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
}
|
||||
ast.Likely {
|
||||
g.write('(')
|
||||
g.expr(it.expr)
|
||||
g.expr(node.expr)
|
||||
g.write(')')
|
||||
}
|
||||
ast.TypeOf {
|
||||
g.gen_typeof_expr(it)
|
||||
g.gen_typeof_expr(node)
|
||||
// TODO: Should this print the V type or the JS type?
|
||||
}
|
||||
ast.ComptimeCall {
|
||||
// TODO
|
||||
}
|
||||
ast.UnsafeExpr {
|
||||
es := it.stmts[0] as ast.ExprStmt
|
||||
es := node.stmts[0] as ast.ExprStmt
|
||||
g.expr(es.expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO
|
||||
fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
|
||||
g.writeln('// assert')
|
||||
|
@ -651,17 +656,17 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
|
|||
mut mod_path := g.file.path.replace('\\', '\\\\')
|
||||
if g.is_test {
|
||||
g.writeln(' g_test_oks++;')
|
||||
g.writeln(' cb_assertion_ok("${mod_path}", ${a.pos.line_nr+1}, "assert ${s_assertion}", "${g.fn_decl.name}()" );')
|
||||
g.writeln(' cb_assertion_ok("$mod_path", ${a.pos.line_nr+1}, "assert $s_assertion", "${g.fn_decl.name}()" );')
|
||||
g.writeln('} else {')
|
||||
g.writeln(' g_test_fails++;')
|
||||
g.writeln(' cb_assertion_failed("${mod_path}", ${a.pos.line_nr+1}, "assert ${s_assertion}", "${g.fn_decl.name}()" );')
|
||||
g.writeln(' cb_assertion_failed("$mod_path", ${a.pos.line_nr+1}, "assert $s_assertion", "${g.fn_decl.name}()" );')
|
||||
g.writeln(' exit(1);')
|
||||
g.writeln('}')
|
||||
return
|
||||
}
|
||||
g.writeln('} else {')
|
||||
g.inc_indent()
|
||||
g.writeln('builtin.eprintln("${mod_path}:${a.pos.line_nr+1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion");')
|
||||
g.writeln('builtin.eprintln("$mod_path:${a.pos.line_nr+1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion");')
|
||||
g.writeln('builtin.exit(1);')
|
||||
g.dec_indent()
|
||||
g.writeln('}')
|
||||
|
@ -686,7 +691,9 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
|||
// `a := 1` | `a,b := 1,2`
|
||||
for i, left in stmt.left {
|
||||
mut op := stmt.op
|
||||
if stmt.op == .decl_assign { op = .assign }
|
||||
if stmt.op == .decl_assign {
|
||||
op = .assign
|
||||
}
|
||||
val := stmt.right[i]
|
||||
mut is_mut := false
|
||||
if left is ast.Ident {
|
||||
|
@ -700,13 +707,10 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
|||
continue
|
||||
}
|
||||
}
|
||||
|
||||
mut styp := g.typ(stmt.left_types[i])
|
||||
|
||||
if !g.inside_loop && styp.len > 0 {
|
||||
g.doc.gen_typ(styp)
|
||||
}
|
||||
|
||||
if stmt.op == .decl_assign {
|
||||
if g.inside_loop || is_mut {
|
||||
g.write('let ')
|
||||
|
@ -724,7 +728,6 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
|||
g.write(' $op ')
|
||||
g.expr(val)
|
||||
}
|
||||
|
||||
if g.inside_loop {
|
||||
g.write('; ')
|
||||
} else {
|
||||
|
@ -753,9 +756,9 @@ fn (mut g JsGen) gen_branch_stmt(it ast.BranchStmt) {
|
|||
fn (mut g JsGen) gen_const_decl(it ast.ConstDecl) {
|
||||
for field in it.fields {
|
||||
g.doc.gen_const(g.typ(field.typ))
|
||||
|
||||
if field.is_pub { g.push_pub_var(field.name) }
|
||||
|
||||
if field.is_pub {
|
||||
g.push_pub_var(field.name)
|
||||
}
|
||||
g.write('const ${g.js_name(field.name)} = ')
|
||||
g.expr(field.expr)
|
||||
g.writeln(';')
|
||||
|
@ -794,7 +797,9 @@ fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) {
|
|||
|
||||
fn (mut g JsGen) gen_expr_stmt(it ast.ExprStmt) {
|
||||
g.expr(it.expr)
|
||||
if !it.is_expr && it.expr !is ast.IfExpr && !g.inside_ternary { g.writeln(';') }
|
||||
if !it.is_expr && it.expr !is ast.IfExpr && !g.inside_ternary {
|
||||
g.writeln(';')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
||||
|
@ -811,7 +816,9 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
|
|||
fn fn_has_go(it ast.FnDecl) bool {
|
||||
mut has_go := false
|
||||
for stmt in it.stmts {
|
||||
if stmt is ast.GoStmt { has_go = true }
|
||||
if stmt is ast.GoStmt {
|
||||
has_go = true
|
||||
}
|
||||
}
|
||||
return has_go
|
||||
}
|
||||
|
@ -836,12 +843,9 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
|||
if c in [`+`, `-`, `*`, `/`] {
|
||||
name = util.replace_op(name)
|
||||
}
|
||||
|
||||
// type_name := g.typ(it.return_type)
|
||||
|
||||
// generate jsdoc for the function
|
||||
g.doc.gen_fn(it)
|
||||
|
||||
if has_go {
|
||||
g.write('async ')
|
||||
}
|
||||
|
@ -849,25 +853,21 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
|||
g.write('function ')
|
||||
}
|
||||
g.write('${name}(')
|
||||
|
||||
if it.is_pub && !it.is_method {
|
||||
g.push_pub_var(name)
|
||||
}
|
||||
}
|
||||
|
||||
mut args := it.args
|
||||
if it.is_method {
|
||||
args = args[1..]
|
||||
}
|
||||
g.fn_args(args, it.is_variadic)
|
||||
g.writeln(') {')
|
||||
|
||||
if it.is_method {
|
||||
g.inc_indent()
|
||||
g.writeln('const ${it.args[0].name} = this;')
|
||||
g.dec_indent()
|
||||
}
|
||||
|
||||
g.stmts(it.stmts)
|
||||
g.write('}')
|
||||
if is_main {
|
||||
|
@ -876,7 +876,6 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
|||
if !it.is_anon && !it.is_method {
|
||||
g.writeln('\n')
|
||||
}
|
||||
|
||||
g.fn_decl = voidptr(0)
|
||||
}
|
||||
|
||||
|
@ -922,8 +921,9 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
|
|||
if it.is_range {
|
||||
// `for x in 1..10 {`
|
||||
mut i := it.val_var
|
||||
if i in ['', '_'] { i = g.new_tmp_var() }
|
||||
|
||||
if i in ['', '_'] {
|
||||
i = g.new_tmp_var()
|
||||
}
|
||||
g.inside_loop = true
|
||||
g.write('for (let $i = ')
|
||||
g.expr(it.cond)
|
||||
|
@ -1013,7 +1013,6 @@ fn (mut g JsGen) gen_interface_decl(it ast.InterfaceDecl) {
|
|||
// JS is dynamically typed, so we don't need any codegen at all
|
||||
// We just need the JSDoc so TypeScript type checking works
|
||||
g.doc.gen_interface(it)
|
||||
|
||||
// This is a hack to make the interface's type accessible outside its namespace
|
||||
// TODO: interfaces are always `pub`?
|
||||
name := g.js_name(it.name)
|
||||
|
@ -1026,7 +1025,6 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) {
|
|||
g.write('return;')
|
||||
return
|
||||
}
|
||||
|
||||
g.write('return ')
|
||||
if it.exprs.len == 1 {
|
||||
g.expr(it.exprs[0])
|
||||
|
@ -1050,7 +1048,9 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
|||
} else {
|
||||
g.write('${g.to_js_typ_val(field.typ)}')
|
||||
}
|
||||
if i < node.fields.len - 1 { g.write(', ') }
|
||||
if i < node.fields.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
g.writeln(' }) {')
|
||||
g.inc_indent()
|
||||
|
@ -1059,22 +1059,26 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
|||
}
|
||||
g.dec_indent()
|
||||
g.writeln('};')
|
||||
|
||||
g.writeln('${g.js_name(node.name)}.prototype = {')
|
||||
g.inc_indent()
|
||||
|
||||
fns := g.method_fn_decls[node.name]
|
||||
|
||||
for i, field in node.fields {
|
||||
typ := g.typ(field.typ)
|
||||
g.doc.gen_typ(typ)
|
||||
g.write('$field.name: ${g.to_js_typ_val(field.typ)}')
|
||||
if i < node.fields.len - 1 || fns.len > 0 { g.writeln(',') } else { g.writeln('') }
|
||||
if i < node.fields.len - 1 || fns.len > 0 {
|
||||
g.writeln(',')
|
||||
} else {
|
||||
g.writeln('')
|
||||
}
|
||||
}
|
||||
|
||||
for i, cfn in fns {
|
||||
g.gen_method_decl(cfn)
|
||||
if i < fns.len - 1 { g.writeln(',') } else { g.writeln('') }
|
||||
if i < fns.len - 1 {
|
||||
g.writeln(',')
|
||||
} else {
|
||||
g.writeln('')
|
||||
}
|
||||
}
|
||||
g.dec_indent()
|
||||
g.writeln('};\n')
|
||||
|
@ -1141,7 +1145,6 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
if it.is_method { // foo.bar.baz()
|
||||
sym := g.table.get_type_symbol(it.receiver_type)
|
||||
g.write('.')
|
||||
|
||||
if sym.kind == .array && it.name in ['map', 'filter'] {
|
||||
// Prevent 'it' from getting shadowed inside the match
|
||||
node := it
|
||||
|
@ -1166,7 +1169,8 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
return
|
||||
}
|
||||
}
|
||||
} else {}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
g.write('it => ')
|
||||
g.expr(node.args[0].expr)
|
||||
|
@ -1204,7 +1208,6 @@ fn (mut g JsGen) gen_lock_expr(node ast.LockExpr) {
|
|||
|
||||
fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||
type_sym := g.table.get_type_symbol(node.typ)
|
||||
|
||||
// one line ?:
|
||||
if node.is_expr && node.branches.len >= 2 && node.has_else && type_sym.kind != .void {
|
||||
// `x := if a > b { } else if { } else { }`
|
||||
|
@ -1286,7 +1289,9 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
|
|||
g.write('.get(')
|
||||
}
|
||||
g.expr(expr.index)
|
||||
if !expr.is_setter { g.write(')') }
|
||||
if !expr.is_setter {
|
||||
g.write(')')
|
||||
}
|
||||
} else if left_typ.kind == .string {
|
||||
if expr.is_setter {
|
||||
// TODO: What's the best way to do this?
|
||||
|
@ -1309,35 +1314,46 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
|
|||
fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
||||
l_sym := g.table.get_type_symbol(it.left_type)
|
||||
r_sym := g.table.get_type_symbol(it.right_type)
|
||||
|
||||
if l_sym.kind == .array && it.op == .left_shift { // arr << 1
|
||||
g.expr(it.left)
|
||||
g.write('.push(')
|
||||
if r_sym.kind == .array { g.write('...') } // arr << [1, 2]
|
||||
if r_sym.kind == .array {
|
||||
g.write('...')
|
||||
} // arr << [1, 2]
|
||||
g.expr(it.right)
|
||||
g.write(')')
|
||||
} else if r_sym.kind in [.array, .map, .string] && it.op in [.key_in, .not_in] {
|
||||
if it.op == .not_in { g.write('!(') }
|
||||
if it.op == .not_in {
|
||||
g.write('!(')
|
||||
}
|
||||
g.expr(it.right)
|
||||
g.write(if r_sym.kind == .map { '.has(' } else { '.includes(' })
|
||||
g.write(if r_sym.kind == .map {
|
||||
'.has('
|
||||
} else {
|
||||
'.includes('
|
||||
})
|
||||
g.expr(it.left)
|
||||
g.write(')')
|
||||
if it.op == .not_in { g.write(')') }
|
||||
if it.op == .not_in {
|
||||
g.write(')')
|
||||
}
|
||||
} else if it.op in [.key_is, .not_is] { // foo is Foo
|
||||
if it.op == .not_is { g.write('!(') }
|
||||
if it.op == .not_is {
|
||||
g.write('!(')
|
||||
}
|
||||
g.expr(it.left)
|
||||
g.write(' instanceof ')
|
||||
g.write(g.typ(it.right_type))
|
||||
if it.op == .not_is { g.write(')') }
|
||||
if it.op == .not_is {
|
||||
g.write(')')
|
||||
}
|
||||
} else {
|
||||
both_are_int := int(it.left_type) in table.integer_type_idxs && int(it.right_type) in table.integer_type_idxs
|
||||
|
||||
both_are_int := int(it.left_type) in table.integer_type_idxs &&
|
||||
int(it.right_type) in table.integer_type_idxs
|
||||
if it.op == .div && both_are_int {
|
||||
g.write('parseInt(')
|
||||
}
|
||||
|
||||
g.expr(it.left)
|
||||
|
||||
// in js == is non-strict & === is strict, always do strict
|
||||
if it.op == .eq {
|
||||
g.write(' === ')
|
||||
|
@ -1346,9 +1362,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
|||
} else {
|
||||
g.write(' $it.op ')
|
||||
}
|
||||
|
||||
g.expr(it.right)
|
||||
|
||||
// Int division: 2.5 -> 2 by prepending |0
|
||||
if it.op == .div && both_are_int {
|
||||
g.write(',10)')
|
||||
|
@ -1356,7 +1370,6 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) {
|
||||
// key_typ_sym := g.table.get_type_symbol(it.key_type)
|
||||
// value_typ_sym := g.table.get_type_symbol(it.value_type)
|
||||
|
@ -1407,7 +1420,6 @@ fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
|
|||
g.expr(expr)
|
||||
} else {
|
||||
sym := g.table.get_type_symbol(it.expr_types[i])
|
||||
|
||||
g.expr(expr)
|
||||
if sym.kind == .struct_ && sym.has_method('str') {
|
||||
g.write('.str()')
|
||||
|
@ -1446,7 +1458,7 @@ fn (mut g JsGen) gen_typeof_expr(it ast.TypeOf) {
|
|||
} else if sym.kind == .array_fixed {
|
||||
fixed_info := sym.info as table.ArrayFixed
|
||||
typ_name := g.table.get_type_name(fixed_info.elem_type)
|
||||
g.write('"[$fixed_info.size]${typ_name}"')
|
||||
g.write('"[$fixed_info.size]$typ_name"')
|
||||
} else if sym.kind == .function {
|
||||
info := sym.info as table.FnType
|
||||
fn_info := info.func
|
||||
|
@ -1463,6 +1475,6 @@ fn (mut g JsGen) gen_typeof_expr(it ast.TypeOf) {
|
|||
}
|
||||
g.write('"$repr"')
|
||||
} else {
|
||||
g.write('"${sym.name}"')
|
||||
g.write('"$sym.name"')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ import v.ast
|
|||
import v.table
|
||||
|
||||
fn (mut p Parser) assign_stmt() ast.Stmt {
|
||||
return p.partial_assign_stmt(p.expr_list())
|
||||
exprs, comments := p.expr_list()
|
||||
return p.partial_assign_stmt(exprs, comments)
|
||||
}
|
||||
|
||||
fn (mut p Parser) check_undefined_variables(exprs []ast.Expr, val ast.Expr) {
|
||||
|
@ -77,12 +78,15 @@ fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt {
|
||||
fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comment) ast.Stmt {
|
||||
p.is_stmt_ident = false
|
||||
op := p.tok.kind
|
||||
pos := p.tok.position()
|
||||
p.next()
|
||||
right := p.expr_list()
|
||||
right, right_comments := p.expr_list()
|
||||
mut comments := []ast.Comment{cap: left_comments.len + right_comments.len}
|
||||
comments << left_comments
|
||||
comments << right_comments
|
||||
mut has_cross_var := false
|
||||
if op == .decl_assign {
|
||||
// a, b := a + 1, b
|
||||
|
@ -155,6 +159,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt {
|
|||
op: op
|
||||
left: left
|
||||
right: right
|
||||
comments: comments
|
||||
pos: pos
|
||||
has_cross_var: has_cross_var
|
||||
is_simple: p.inside_for && p.tok.kind == .lcbr
|
||||
|
|
|
@ -37,12 +37,10 @@ fn (mut p Parser) array_init() ast.ArrayInit {
|
|||
} else {
|
||||
// [1,2,3] or [const]byte
|
||||
for i := 0; p.tok.kind != .rsbr; i++ {
|
||||
expr := p.expr(0)
|
||||
exprs << expr
|
||||
exprs << p.expr(0)
|
||||
if p.tok.kind == .comma {
|
||||
p.next()
|
||||
}
|
||||
// p.check_comment()
|
||||
}
|
||||
line_nr := p.tok.line_nr
|
||||
$if tinyc {
|
||||
|
|
|
@ -31,5 +31,3 @@ fn (mut p Parser) lock_expr() ast.LockExpr {
|
|||
pos: pos
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,10 +21,8 @@ pub fn (mut p Parser) parse_array_type() table.Type {
|
|||
p.check(.rsbr)
|
||||
elem_type := p.parse_type()
|
||||
mut nr_dims := 1
|
||||
|
||||
// detect attr
|
||||
not_attr := p.peek_tok.kind != .name && p.peek_tok2.kind !in [.semicolon, .rsbr]
|
||||
|
||||
for p.tok.kind == .lsbr && not_attr {
|
||||
p.next()
|
||||
p.check(.rsbr)
|
||||
|
@ -100,7 +98,6 @@ pub fn (mut p Parser) parse_type_with_mut(is_mut bool) table.Type {
|
|||
|
||||
// Parses any language indicators on a type.
|
||||
pub fn (mut p Parser) parse_language() table.Language {
|
||||
|
||||
language := if p.tok.lit == 'C' {
|
||||
table.Language.c
|
||||
} else if p.tok.lit == 'JS' {
|
||||
|
@ -108,12 +105,10 @@ pub fn (mut p Parser) parse_language() table.Language {
|
|||
} else {
|
||||
table.Language.v
|
||||
}
|
||||
|
||||
if language != .v {
|
||||
p.next()
|
||||
p.check(.dot)
|
||||
}
|
||||
|
||||
return language
|
||||
}
|
||||
|
||||
|
@ -124,7 +119,6 @@ pub fn (mut p Parser) parse_type() table.Type {
|
|||
line_nr := p.tok.line_nr
|
||||
p.next()
|
||||
is_optional = true
|
||||
|
||||
if p.tok.line_nr > line_nr {
|
||||
mut typ := table.void_type
|
||||
if is_optional {
|
||||
|
@ -135,7 +129,6 @@ pub fn (mut p Parser) parse_type() table.Type {
|
|||
}
|
||||
is_shared := p.tok.kind == .key_shared
|
||||
is_atomic := p.tok.kind == .key_atomic
|
||||
|
||||
mut nr_muls := 0
|
||||
if p.tok.kind == .key_mut || is_shared || is_atomic {
|
||||
nr_muls++
|
||||
|
|
|
@ -137,7 +137,7 @@ fn (mut p Parser) parse() ast.File {
|
|||
p.read_first_token()
|
||||
mut stmts := []ast.Stmt{}
|
||||
for p.tok.kind == .comment {
|
||||
stmts << p.comment()
|
||||
stmts << p.comment_stmt()
|
||||
}
|
||||
// module
|
||||
module_decl := p.module_decl()
|
||||
|
@ -149,7 +149,7 @@ fn (mut p Parser) parse() ast.File {
|
|||
continue
|
||||
}
|
||||
if p.tok.kind == .comment {
|
||||
stmts << p.comment()
|
||||
stmts << p.comment_stmt()
|
||||
continue
|
||||
}
|
||||
break
|
||||
|
@ -443,7 +443,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
|
|||
return p.struct_decl()
|
||||
}
|
||||
.comment {
|
||||
return p.comment()
|
||||
return p.comment_stmt()
|
||||
}
|
||||
else {
|
||||
if p.pref.is_script && !p.pref.is_test {
|
||||
|
@ -488,13 +488,21 @@ pub fn (mut p Parser) comment() ast.Comment {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (mut p Parser) comment_stmt() ast.ExprStmt {
|
||||
comment := p.comment()
|
||||
return ast.ExprStmt{
|
||||
expr: comment
|
||||
pos: comment.pos
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut p Parser) eat_comments() []ast.Comment {
|
||||
mut comments := []ast.Comment{}
|
||||
for {
|
||||
if p.tok.kind != .comment {
|
||||
break
|
||||
}
|
||||
comments << p.check_comment()
|
||||
comments << p.comment()
|
||||
}
|
||||
return comments
|
||||
}
|
||||
|
@ -546,7 +554,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
|||
return p.parse_multi_expr(is_top_level)
|
||||
}
|
||||
.comment {
|
||||
return p.comment()
|
||||
return p.comment_stmt()
|
||||
}
|
||||
.key_return {
|
||||
return p.return_stmt()
|
||||
|
@ -622,16 +630,22 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) expr_list() []ast.Expr {
|
||||
fn (mut p Parser) expr_list() ([]ast.Expr, []ast.Comment) {
|
||||
mut exprs := []ast.Expr{}
|
||||
mut comments := []ast.Comment{}
|
||||
for {
|
||||
exprs << p.expr(0)
|
||||
expr := p.expr(0)
|
||||
if expr is ast.Comment {
|
||||
comments << expr
|
||||
} else {
|
||||
exprs << expr
|
||||
if p.tok.kind != .comma {
|
||||
break
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
return exprs
|
||||
}
|
||||
return exprs, comments
|
||||
}
|
||||
|
||||
// when is_top_stmt is true attrs are added to p.attrs
|
||||
|
@ -769,10 +783,10 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
|
|||
// a, mut b ... :=/= // multi-assign
|
||||
// collect things upto hard boundaries
|
||||
tok := p.tok
|
||||
left := p.expr_list()
|
||||
left, left_comments := p.expr_list()
|
||||
left0 := left[0]
|
||||
if p.tok.kind in [.assign, .decl_assign] || p.tok.kind.is_assign() {
|
||||
return p.partial_assign_stmt(left)
|
||||
return p.partial_assign_stmt(left, left_comments)
|
||||
} else if is_top_level && tok.kind !in [.key_if, .key_match, .key_lock, .key_rlock] &&
|
||||
left0 !is ast.CallExpr && left0 !is ast.PostfixExpr && !(left0 is ast.InfixExpr &&
|
||||
(left0 as ast.InfixExpr).op == .left_shift) &&
|
||||
|
@ -783,6 +797,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
|
|||
return ast.ExprStmt{
|
||||
expr: left0
|
||||
pos: tok.position()
|
||||
comments: left_comments
|
||||
is_expr: p.inside_for
|
||||
}
|
||||
}
|
||||
|
@ -791,6 +806,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
|
|||
vals: left
|
||||
}
|
||||
pos: tok.position()
|
||||
comments: left_comments
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1416,10 +1432,11 @@ fn (mut p Parser) return_stmt() ast.Return {
|
|||
}
|
||||
}
|
||||
// return exprs
|
||||
exprs := p.expr_list()
|
||||
exprs, comments := p.expr_list()
|
||||
end_pos := exprs.last().position()
|
||||
return ast.Return{
|
||||
exprs: exprs
|
||||
comments: comments
|
||||
pos: first_pos.extend(end_pos)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
|||
mut node := ast.Expr{}
|
||||
is_stmt_ident := p.is_stmt_ident
|
||||
p.is_stmt_ident = false
|
||||
if !p.pref.is_fmt {
|
||||
p.eat_comments()
|
||||
}
|
||||
// Prefix
|
||||
match p.tok.kind {
|
||||
.key_mut, .key_shared, .key_atomic, .key_static {
|
||||
|
@ -33,6 +35,9 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
|||
.string {
|
||||
node = p.string_expr()
|
||||
}
|
||||
.comment {
|
||||
node = p.comment()
|
||||
}
|
||||
.dot {
|
||||
// .enum_val
|
||||
node = p.enum_val()
|
||||
|
|
|
@ -165,7 +165,6 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
|
|||
} else if kind == .delete && n != 'from' {
|
||||
p.error('expecting `from`')
|
||||
}
|
||||
|
||||
mut table_type := table.Type(0)
|
||||
mut where_expr := ast.Expr{}
|
||||
if kind == .insert {
|
||||
|
|
Loading…
Reference in New Issue