2022-01-04 10:21:08 +01:00
|
|
|
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
2020-05-25 05:32:33 +02:00
|
|
|
// Use of this source code is governed by an MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
2021-02-02 15:41:51 +01:00
|
|
|
module c
|
2020-05-25 05:32:33 +02:00
|
|
|
|
2021-01-31 18:22:42 +01:00
|
|
|
import os
|
2020-06-08 13:30:17 +02:00
|
|
|
import v.ast
|
2020-07-01 00:53:53 +02:00
|
|
|
import v.util
|
2021-04-02 17:52:30 +02:00
|
|
|
import v.pref
|
2020-05-25 05:32:33 +02:00
|
|
|
|
2021-01-05 15:11:43 +01:00
|
|
|
fn (mut g Gen) comptime_selector(node ast.ComptimeSelector) {
|
|
|
|
g.expr(node.left)
|
|
|
|
if node.left_type.is_ptr() {
|
|
|
|
g.write('->')
|
|
|
|
} else {
|
|
|
|
g.write('.')
|
|
|
|
}
|
|
|
|
// check for field.name
|
|
|
|
if node.field_expr is ast.SelectorExpr {
|
|
|
|
if node.field_expr.expr is ast.Ident {
|
2021-11-15 14:47:29 +01:00
|
|
|
if node.field_expr.expr.name == g.comptime_for_field_var
|
2021-01-23 09:33:22 +01:00
|
|
|
&& node.field_expr.field_name == 'name' {
|
2022-05-04 06:06:52 +02:00
|
|
|
field_name := g.comptime_for_field_value.name
|
|
|
|
left_sym := g.table.sym(g.unwrap_generic(node.left_type))
|
|
|
|
_ := g.table.find_field_with_embeds(left_sym, field_name) or {
|
|
|
|
g.error('`$node.left` has no field named `$field_name`', node.left.pos())
|
|
|
|
}
|
|
|
|
g.write(c_name(field_name))
|
2021-01-05 15:11:43 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.expr(node.field_expr)
|
|
|
|
}
|
|
|
|
|
2021-12-04 18:43:19 +01:00
|
|
|
fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
|
2021-01-14 15:20:11 +01:00
|
|
|
if node.is_embed {
|
2021-01-31 18:22:42 +01:00
|
|
|
// $embed_file('/path/to/file')
|
2021-12-04 18:43:19 +01:00
|
|
|
g.gen_embed_file_init(mut node)
|
2021-01-14 15:20:11 +01:00
|
|
|
return
|
|
|
|
}
|
2021-01-31 18:22:42 +01:00
|
|
|
if node.method_name == 'env' {
|
|
|
|
// $env('ENV_VAR_NAME')
|
|
|
|
val := util.cescaped_path(os.getenv(node.args_var))
|
|
|
|
g.write('_SLIT("$val")')
|
|
|
|
return
|
|
|
|
}
|
2020-06-08 13:30:17 +02:00
|
|
|
if node.is_vweb {
|
2020-11-26 18:40:31 +01:00
|
|
|
is_html := node.method_name == 'html'
|
2021-09-19 22:22:26 +02:00
|
|
|
mut cur_line := ''
|
|
|
|
|
|
|
|
if !is_html {
|
|
|
|
cur_line = g.go_before_stmt(0)
|
|
|
|
}
|
|
|
|
|
2020-06-08 13:30:17 +02:00
|
|
|
for stmt in node.vweb_tmpl.stmts {
|
|
|
|
if stmt is ast.FnDecl {
|
|
|
|
// insert stmts from vweb_tmpl fn
|
2020-07-09 17:14:14 +02:00
|
|
|
if stmt.name.starts_with('main.vweb_tmpl') {
|
2020-11-26 18:40:31 +01:00
|
|
|
if is_html {
|
|
|
|
g.inside_vweb_tmpl = true
|
|
|
|
}
|
2021-09-19 22:22:26 +02:00
|
|
|
g.stmts(stmt.stmts.filter(it !is ast.Return))
|
2020-06-24 22:12:33 +02:00
|
|
|
g.inside_vweb_tmpl = false
|
2020-06-08 13:30:17 +02:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-19 22:22:26 +02:00
|
|
|
|
2021-12-08 09:12:02 +01:00
|
|
|
fn_name := g.fn_decl.name.replace('.', '__') + node.pos.pos.str()
|
2020-11-26 18:40:31 +01:00
|
|
|
if is_html {
|
|
|
|
// return vweb html template
|
2021-12-08 09:12:02 +01:00
|
|
|
g.writeln('vweb__Context_html(&app->Context, _tmpl_res_$fn_name); strings__Builder_free(&sb_$fn_name); string_free(&_tmpl_res_$fn_name);')
|
2020-11-26 18:40:31 +01:00
|
|
|
} else {
|
|
|
|
// return $tmpl string
|
2021-09-19 22:22:26 +02:00
|
|
|
g.write(cur_line)
|
|
|
|
if g.inside_return {
|
|
|
|
g.write('return ')
|
|
|
|
}
|
|
|
|
g.write('_tmpl_res_$fn_name')
|
2020-11-26 18:40:31 +01:00
|
|
|
}
|
2020-06-08 13:30:17 +02:00
|
|
|
return
|
2020-05-25 05:32:33 +02:00
|
|
|
}
|
2021-12-19 17:25:18 +01:00
|
|
|
sym := g.table.sym(g.unwrap_generic(node.left_type))
|
2021-12-12 18:42:40 +01:00
|
|
|
g.trace_autofree('// \$method call. sym="$sym.name"')
|
2020-07-03 15:10:39 +02:00
|
|
|
if node.method_name == 'method' {
|
|
|
|
// `app.$method()`
|
2021-12-12 18:42:40 +01:00
|
|
|
m := sym.find_method(g.comptime_for_method) or { return }
|
2020-07-03 15:10:39 +02:00
|
|
|
/*
|
|
|
|
vals := m.attrs[0].split('/')
|
|
|
|
args := vals.filter(it.starts_with(':')).map(it[1..])
|
|
|
|
println(vals)
|
|
|
|
for val in vals {
|
|
|
|
}
|
|
|
|
*/
|
2021-03-11 14:04:34 +01:00
|
|
|
expand_strs := if node.args.len > 0 && m.params.len - 1 >= node.args.len {
|
|
|
|
arg := node.args[node.args.len - 1]
|
|
|
|
param := m.params[node.args.len]
|
|
|
|
|
|
|
|
arg.expr is ast.Ident && g.table.type_to_str(arg.typ) == '[]string'
|
|
|
|
&& g.table.type_to_str(param.typ) != '[]string'
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
// check argument length and types
|
|
|
|
if m.params.len - 1 != node.args.len && !expand_strs {
|
2022-01-10 11:03:50 +01:00
|
|
|
if g.inside_call {
|
|
|
|
g.error('expected ${m.params.len - 1} arguments to method ${sym.name}.$m.name, but got $node.args.len',
|
|
|
|
node.pos)
|
|
|
|
} else {
|
|
|
|
// do not generate anything if the argument lengths don't match
|
|
|
|
g.writeln('/* skipping ${sym.name}.$m.name due to mismatched arguments list */')
|
|
|
|
// g.writeln('println(_SLIT("skipping ${node.sym.name}.$m.name due to mismatched arguments list"));')
|
|
|
|
// eprintln('info: skipping ${node.sym.name}.$m.name due to mismatched arguments list\n' +
|
|
|
|
//'method.params: $m.params, args: $node.args\n\n')
|
|
|
|
// verror('expected ${m.params.len-1} arguments to method ${node.sym.name}.$m.name, but got $node.args.len')
|
|
|
|
}
|
2021-03-11 14:04:34 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
// TODO: check argument types
|
2021-12-12 18:42:40 +01:00
|
|
|
g.write('${util.no_dots(sym.name)}_${g.comptime_for_method}(')
|
2021-03-11 14:04:34 +01:00
|
|
|
|
|
|
|
// try to see if we need to pass a pointer
|
|
|
|
if node.left is ast.Ident {
|
2022-02-28 16:13:29 +01:00
|
|
|
if node.left.obj is ast.Var {
|
|
|
|
if m.params[0].typ.is_ptr() && !node.left.obj.typ.is_ptr() {
|
2021-03-11 14:04:34 +01:00
|
|
|
g.write('&')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-03 15:10:39 +02:00
|
|
|
g.expr(node.left)
|
2020-09-27 03:32:56 +02:00
|
|
|
if m.params.len > 1 {
|
2020-07-03 15:10:39 +02:00
|
|
|
g.write(', ')
|
|
|
|
}
|
2020-09-27 03:32:56 +02:00
|
|
|
for i in 1 .. m.params.len {
|
2020-07-23 17:19:37 +02:00
|
|
|
if node.left is ast.Ident {
|
2020-11-21 00:05:57 +01:00
|
|
|
if m.params[i].name == node.left.name {
|
2020-07-23 17:19:37 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2021-03-11 14:04:34 +01:00
|
|
|
if i - 1 < node.args.len - 1 {
|
|
|
|
g.expr(node.args[i - 1].expr)
|
2020-07-03 15:10:39 +02:00
|
|
|
g.write(', ')
|
2021-03-11 14:04:34 +01:00
|
|
|
} else if !expand_strs && i == node.args.len {
|
|
|
|
g.expr(node.args[i - 1].expr)
|
|
|
|
break
|
|
|
|
} else {
|
|
|
|
// last argument; try to expand if it's []string
|
|
|
|
idx := i - node.args.len
|
2021-04-02 00:57:09 +02:00
|
|
|
if m.params[i].typ.is_int() || m.params[i].typ.idx() == ast.bool_type_idx {
|
2021-03-11 14:04:34 +01:00
|
|
|
// Gets the type name and cast the string to the type with the string_<type> function
|
2021-03-19 21:51:52 +01:00
|
|
|
type_name := g.table.type_symbols[int(m.params[i].typ)].str()
|
2021-03-11 14:04:34 +01:00
|
|
|
g.write('string_${type_name}(((string*)${node.args[node.args.len - 1]}.data) [$idx])')
|
|
|
|
} else {
|
|
|
|
g.write('((string*)${node.args[node.args.len - 1]}.data) [$idx] ')
|
|
|
|
}
|
|
|
|
if i < m.params.len - 1 {
|
|
|
|
g.write(', ')
|
|
|
|
}
|
2020-07-03 15:10:39 +02:00
|
|
|
}
|
|
|
|
}
|
2022-01-07 11:59:27 +01:00
|
|
|
if g.inside_call {
|
|
|
|
g.write(')')
|
|
|
|
} else {
|
|
|
|
g.write(');')
|
|
|
|
}
|
2020-07-03 15:10:39 +02:00
|
|
|
return
|
|
|
|
}
|
2021-01-30 15:24:16 +01:00
|
|
|
mut j := 0
|
2021-12-12 18:42:40 +01:00
|
|
|
for method in sym.methods {
|
2021-04-02 00:57:09 +02:00
|
|
|
// if method.return_type != ast.void_type {
|
2021-01-30 15:24:16 +01:00
|
|
|
if method.return_type != node.result_type {
|
2020-06-08 13:30:17 +02:00
|
|
|
continue
|
|
|
|
}
|
2020-09-27 03:32:56 +02:00
|
|
|
if method.params.len != 1 {
|
2020-07-03 15:10:39 +02:00
|
|
|
continue
|
|
|
|
}
|
2020-06-08 13:30:17 +02:00
|
|
|
// receiver := method.args[0]
|
|
|
|
// if !p.expr_var.ptr {
|
|
|
|
// p.error('`$p.expr_var.name` needs to be a reference')
|
2020-05-25 05:32:33 +02:00
|
|
|
// }
|
2020-06-08 13:30:17 +02:00
|
|
|
amp := '' // if receiver.is_mut && !p.expr_var.ptr { '&' } else { '' }
|
2021-01-30 15:24:16 +01:00
|
|
|
if node.is_vweb {
|
|
|
|
if j > 0 {
|
|
|
|
g.write(' else ')
|
|
|
|
}
|
2021-05-24 10:38:31 +02:00
|
|
|
g.write('if (string__eq($node.method_name, _SLIT("$method.name"))) ')
|
2020-06-08 13:30:17 +02:00
|
|
|
}
|
2021-12-12 18:42:40 +01:00
|
|
|
g.write('${util.no_dots(sym.name)}_${method.name}($amp ')
|
2020-06-08 13:30:17 +02:00
|
|
|
g.expr(node.left)
|
|
|
|
g.writeln(');')
|
|
|
|
j++
|
2020-05-25 05:32:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 00:57:09 +02:00
|
|
|
fn cgen_attrs(attrs []ast.Attr) []string {
|
2020-08-10 02:00:14 +02:00
|
|
|
mut res := []string{cap: attrs.len}
|
|
|
|
for attr in attrs {
|
|
|
|
// we currently don't quote 'arg' (otherwise we could just use `s := attr.str()`)
|
|
|
|
mut s := attr.name
|
|
|
|
if attr.arg.len > 0 {
|
|
|
|
s += ': $attr.arg'
|
|
|
|
}
|
2020-12-03 16:02:48 +01:00
|
|
|
res << '_SLIT("$s")'
|
2020-08-10 02:00:14 +02:00
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2021-11-15 14:47:29 +01:00
|
|
|
fn (mut g Gen) comptime_at(node ast.AtExpr) {
|
2020-11-05 09:12:32 +01:00
|
|
|
if node.kind == .vmod_file {
|
2022-03-18 20:50:34 +01:00
|
|
|
val := cescape_nonascii(util.smart_quote(node.val, false))
|
2020-12-03 16:02:48 +01:00
|
|
|
g.write('_SLIT("$val")')
|
2020-11-05 09:12:32 +01:00
|
|
|
} else {
|
2020-11-27 10:16:57 +01:00
|
|
|
val := node.val.replace('\\', '\\\\')
|
2020-12-03 16:02:48 +01:00
|
|
|
g.write('_SLIT("$val")')
|
2020-11-05 09:12:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-15 14:47:29 +01:00
|
|
|
fn (mut g Gen) comptime_if(node ast.IfExpr) {
|
2021-04-02 17:52:30 +02:00
|
|
|
if !node.is_expr && !node.has_else && node.branches.len == 1 {
|
|
|
|
if node.branches[0].stmts.len == 0 {
|
|
|
|
// empty ifdef; result of target OS != conditional => skip
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !g.pref.output_cross_c {
|
|
|
|
if node.branches[0].cond is ast.Ident {
|
|
|
|
if g.pref.os == (pref.os_from_string(node.branches[0].cond.name) or {
|
|
|
|
pref.OS._auto
|
|
|
|
}) {
|
|
|
|
// Same target OS as the conditional...
|
|
|
|
// => skip the #if defined ... #endif wrapper
|
|
|
|
// and just generate the branch statements:
|
|
|
|
g.indent--
|
|
|
|
g.stmts(node.branches[0].stmts)
|
|
|
|
g.indent++
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-18 00:58:54 +02:00
|
|
|
line := if node.is_expr {
|
|
|
|
stmt_str := g.go_before_stmt(0)
|
2021-03-09 12:03:25 +01:00
|
|
|
g.write(util.tabs(g.indent))
|
2020-09-18 00:58:54 +02:00
|
|
|
stmt_str.trim_space()
|
2020-10-15 22:12:59 +02:00
|
|
|
} else {
|
|
|
|
''
|
|
|
|
}
|
2021-11-15 14:47:29 +01:00
|
|
|
mut comptime_if_stmts_skip := false // don't write any statements if the condition is false
|
2021-05-11 08:30:01 +02:00
|
|
|
// (so that for example windows calls don't get generated inside `$if macos` which
|
|
|
|
// will lead to compilation errors)
|
|
|
|
|
2020-09-18 00:58:54 +02:00
|
|
|
for i, branch in node.branches {
|
|
|
|
start_pos := g.out.len
|
|
|
|
if i == node.branches.len - 1 && node.has_else {
|
|
|
|
g.writeln('#else')
|
2021-11-15 14:47:29 +01:00
|
|
|
comptime_if_stmts_skip = false
|
2020-09-18 00:58:54 +02:00
|
|
|
} else {
|
|
|
|
if i == 0 {
|
|
|
|
g.write('#if ')
|
|
|
|
} else {
|
|
|
|
g.write('#elif ')
|
|
|
|
}
|
2021-11-15 14:47:29 +01:00
|
|
|
comptime_if_stmts_skip = !g.comptime_if_cond(branch.cond, branch.pkg_exist)
|
2020-09-18 00:58:54 +02:00
|
|
|
g.writeln('')
|
2020-07-25 00:02:44 +02:00
|
|
|
}
|
2020-09-18 00:58:54 +02:00
|
|
|
expr_str := g.out.last_n(g.out.len - start_pos).trim_space()
|
|
|
|
g.defer_ifdef = expr_str
|
|
|
|
if node.is_expr {
|
|
|
|
len := branch.stmts.len
|
|
|
|
if len > 0 {
|
2022-04-17 13:08:43 +02:00
|
|
|
last := branch.stmts.last() as ast.ExprStmt
|
2020-09-18 00:58:54 +02:00
|
|
|
if len > 1 {
|
|
|
|
tmp := g.new_tmp_var()
|
|
|
|
styp := g.typ(last.typ)
|
|
|
|
g.indent++
|
|
|
|
g.writeln('$styp $tmp;')
|
|
|
|
g.writeln('{')
|
2022-04-17 13:08:43 +02:00
|
|
|
g.stmts(branch.stmts[..len - 1])
|
2020-09-18 00:58:54 +02:00
|
|
|
g.write('\t$tmp = ')
|
|
|
|
g.stmt(last)
|
|
|
|
g.writeln('}')
|
|
|
|
g.indent--
|
|
|
|
g.writeln('$line $tmp;')
|
|
|
|
} else {
|
|
|
|
g.write('$line ')
|
|
|
|
g.stmt(last)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Only wrap the contents in {} if we're inside a function, not on the top level scope
|
2022-05-20 17:30:16 +02:00
|
|
|
should_create_scope := unsafe { g.fn_decl != 0 }
|
2020-10-15 22:12:59 +02:00
|
|
|
if should_create_scope {
|
|
|
|
g.writeln('{')
|
|
|
|
}
|
2021-11-15 14:47:29 +01:00
|
|
|
if !comptime_if_stmts_skip {
|
2021-01-08 18:39:58 +01:00
|
|
|
g.stmts(branch.stmts)
|
|
|
|
}
|
2020-10-15 22:12:59 +02:00
|
|
|
if should_create_scope {
|
|
|
|
g.writeln('}')
|
|
|
|
}
|
2020-07-25 00:02:44 +02:00
|
|
|
}
|
2020-06-08 13:30:17 +02:00
|
|
|
g.defer_ifdef = ''
|
|
|
|
}
|
2021-03-19 10:14:52 +01:00
|
|
|
g.writeln('#endif')
|
2020-09-18 00:58:54 +02:00
|
|
|
}
|
|
|
|
|
2021-05-11 08:30:01 +02:00
|
|
|
// returns the value of the bool comptime expression
|
2022-01-12 10:40:11 +01:00
|
|
|
// returning `false` means the statements inside the $if can be skipped
|
2021-11-15 14:47:29 +01:00
|
|
|
fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) bool {
|
2020-11-25 12:09:40 +01:00
|
|
|
match cond {
|
2020-12-11 04:46:06 +01:00
|
|
|
ast.BoolLiteral {
|
|
|
|
g.expr(cond)
|
2021-01-25 17:08:02 +01:00
|
|
|
return true
|
2020-12-11 04:46:06 +01:00
|
|
|
}
|
2020-09-18 00:58:54 +02:00
|
|
|
ast.ParExpr {
|
|
|
|
g.write('(')
|
2021-11-15 14:47:29 +01:00
|
|
|
is_cond_true := g.comptime_if_cond(cond.expr, pkg_exist)
|
2020-09-18 00:58:54 +02:00
|
|
|
g.write(')')
|
2021-01-25 17:08:02 +01:00
|
|
|
return is_cond_true
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
|
|
|
ast.PrefixExpr {
|
2020-09-18 00:58:54 +02:00
|
|
|
g.write(cond.op.str())
|
2021-11-15 14:47:29 +01:00
|
|
|
return g.comptime_if_cond(cond.right, pkg_exist)
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
|
|
|
ast.PostfixExpr {
|
2021-11-15 14:47:29 +01:00
|
|
|
ifdef := g.comptime_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
|
2022-02-11 14:52:33 +01:00
|
|
|
verror(err.msg())
|
2021-01-25 17:08:02 +01:00
|
|
|
return false
|
2020-12-11 04:46:06 +01:00
|
|
|
}
|
2020-09-18 00:58:54 +02:00
|
|
|
g.write('defined($ifdef)')
|
2021-01-25 17:08:02 +01:00
|
|
|
return true
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
|
|
|
ast.InfixExpr {
|
2020-09-18 00:58:54 +02:00
|
|
|
match cond.op {
|
|
|
|
.and, .logical_or {
|
2021-11-15 14:47:29 +01:00
|
|
|
l := g.comptime_if_cond(cond.left, pkg_exist)
|
2020-09-18 00:58:54 +02:00
|
|
|
g.write(' $cond.op ')
|
2021-11-15 14:47:29 +01:00
|
|
|
r := g.comptime_if_cond(cond.right, pkg_exist)
|
2021-03-13 07:45:50 +01:00
|
|
|
return if cond.op == .and { l && r } else { l || r }
|
2020-09-18 00:58:54 +02:00
|
|
|
}
|
|
|
|
.key_is, .not_is {
|
2021-01-06 18:58:53 +01:00
|
|
|
left := cond.left
|
|
|
|
mut name := ''
|
2022-02-21 16:42:54 +01:00
|
|
|
if left is ast.TypeNode && cond.right is ast.ComptimeType {
|
|
|
|
checked_type := g.unwrap_generic(left.typ)
|
|
|
|
is_true := g.table.is_comptime_type(checked_type, cond.right)
|
|
|
|
if cond.op == .key_is {
|
|
|
|
if is_true {
|
|
|
|
g.write('1')
|
|
|
|
} else {
|
|
|
|
g.write('0')
|
|
|
|
}
|
|
|
|
return is_true
|
|
|
|
} else {
|
|
|
|
if is_true {
|
|
|
|
g.write('0')
|
|
|
|
} else {
|
|
|
|
g.write('1')
|
|
|
|
}
|
|
|
|
return !is_true
|
|
|
|
}
|
|
|
|
}
|
2021-04-02 00:57:09 +02:00
|
|
|
mut exp_type := ast.Type(0)
|
|
|
|
got_type := (cond.right as ast.TypeNode).typ
|
2021-05-11 08:30:01 +02:00
|
|
|
// Handle `$if x is Interface {`
|
|
|
|
// mut matches_interface := 'false'
|
2021-05-11 09:28:11 +02:00
|
|
|
if left is ast.TypeNode && cond.right is ast.TypeNode
|
2021-12-19 17:25:18 +01:00
|
|
|
&& g.table.sym(got_type).kind == .interface_ {
|
2021-05-11 08:30:01 +02:00
|
|
|
// `$if Foo is Interface {`
|
2021-12-19 17:25:18 +01:00
|
|
|
interface_sym := g.table.sym(got_type)
|
2021-05-11 08:30:01 +02:00
|
|
|
if interface_sym.info is ast.Interface {
|
2021-12-19 17:25:18 +01:00
|
|
|
// q := g.table.sym(interface_sym.info.types[0])
|
2021-06-17 11:27:31 +02:00
|
|
|
checked_type := g.unwrap_generic(left.typ)
|
2021-05-11 08:30:01 +02:00
|
|
|
// TODO PERF this check is run twice (also in the checker)
|
|
|
|
// store the result in a field
|
2021-07-02 09:18:04 +02:00
|
|
|
is_true := g.table.does_type_implement_interface(checked_type,
|
2021-05-11 08:30:01 +02:00
|
|
|
got_type)
|
|
|
|
// true // exp_type in interface_sym.info.types
|
|
|
|
if cond.op == .key_is {
|
|
|
|
if is_true {
|
|
|
|
g.write('1')
|
|
|
|
} else {
|
|
|
|
g.write('0')
|
|
|
|
}
|
|
|
|
return is_true
|
|
|
|
} else if cond.op == .not_is {
|
|
|
|
if is_true {
|
|
|
|
g.write('0')
|
|
|
|
} else {
|
|
|
|
g.write('1')
|
|
|
|
}
|
|
|
|
return !is_true
|
|
|
|
}
|
|
|
|
// matches_interface = '/*iface:$got_type $exp_type*/ true'
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
} else if left is ast.SelectorExpr {
|
2022-01-11 15:25:16 +01:00
|
|
|
if left.gkind_field == .typ {
|
|
|
|
exp_type = g.unwrap_generic(left.name_type)
|
|
|
|
} else {
|
2022-01-12 10:40:11 +01:00
|
|
|
name = '${left.expr}.$left.field_name'
|
2022-01-11 15:25:16 +01:00
|
|
|
exp_type = g.comptime_var_type_map[name]
|
|
|
|
}
|
2021-04-02 00:57:09 +02:00
|
|
|
} else if left is ast.TypeNode {
|
2021-01-06 18:58:53 +01:00
|
|
|
// this is only allowed for generics currently, otherwise blocked by checker
|
|
|
|
exp_type = g.unwrap_generic(left.typ)
|
|
|
|
}
|
2021-01-25 17:08:02 +01:00
|
|
|
|
|
|
|
if cond.op == .key_is {
|
2022-03-24 10:45:06 +01:00
|
|
|
g.write('$exp_type.idx() == $got_type.idx()')
|
2021-01-25 17:08:02 +01:00
|
|
|
return exp_type == got_type
|
|
|
|
} else {
|
2022-03-24 10:45:06 +01:00
|
|
|
g.write('$exp_type.idx() != $got_type.idx()')
|
2021-01-25 17:08:02 +01:00
|
|
|
return exp_type != got_type
|
|
|
|
}
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
|
|
|
.eq, .ne {
|
2020-09-18 00:58:54 +02:00
|
|
|
// TODO Implement `$if method.args.len == 1`
|
2020-12-11 04:46:06 +01:00
|
|
|
g.write('1')
|
2021-01-25 17:08:02 +01:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return true
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
2020-09-18 00:58:54 +02:00
|
|
|
}
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
|
|
|
ast.Ident {
|
2021-11-15 14:47:29 +01:00
|
|
|
ifdef := g.comptime_if_to_ifdef(cond.name, false) or { 'true' } // handled in checker
|
2020-09-18 00:58:54 +02:00
|
|
|
g.write('defined($ifdef)')
|
2021-01-25 17:08:02 +01:00
|
|
|
return true
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
2021-07-09 17:17:04 +02:00
|
|
|
ast.ComptimeCall {
|
|
|
|
g.write('$pkg_exist')
|
|
|
|
return true
|
|
|
|
}
|
2020-12-11 04:46:06 +01:00
|
|
|
else {
|
|
|
|
// should be unreachable, but just in case
|
|
|
|
g.write('1')
|
2021-01-25 17:08:02 +01:00
|
|
|
return true
|
2020-12-11 04:46:06 +01:00
|
|
|
}
|
2020-09-18 00:58:54 +02:00
|
|
|
}
|
2020-05-25 05:32:33 +02:00
|
|
|
}
|
2020-07-03 15:10:39 +02:00
|
|
|
|
2021-11-17 07:29:43 +01:00
|
|
|
fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
2021-12-19 17:25:18 +01:00
|
|
|
sym := g.table.sym(g.unwrap_generic(node.typ))
|
2021-03-01 01:01:56 +01:00
|
|
|
g.writeln('/* \$for $node.val_var in ${sym.name}($node.kind.str()) */ {')
|
|
|
|
g.indent++
|
2021-04-02 00:57:09 +02:00
|
|
|
// vweb_result_type := ast.new_type(g.table.find_type_idx('vweb.Result'))
|
2020-07-03 15:10:39 +02:00
|
|
|
mut i := 0
|
2020-12-03 16:02:48 +01:00
|
|
|
// g.writeln('string method = _SLIT("");')
|
2020-07-25 00:02:44 +02:00
|
|
|
if node.kind == .methods {
|
|
|
|
mut methods := sym.methods.filter(it.attrs.len == 0) // methods without attrs first
|
2020-07-25 18:58:23 +02:00
|
|
|
methods_with_attrs := sym.methods.filter(it.attrs.len > 0) // methods with attrs second
|
2020-07-25 00:02:44 +02:00
|
|
|
methods << methods_with_attrs
|
|
|
|
if methods.len > 0 {
|
2021-03-01 01:01:56 +01:00
|
|
|
g.writeln('FunctionData $node.val_var = {0};')
|
2020-07-03 15:10:39 +02:00
|
|
|
}
|
2020-07-25 00:02:44 +02:00
|
|
|
for method in methods { // sym.methods {
|
|
|
|
/*
|
2021-04-02 00:57:09 +02:00
|
|
|
if method.return_type != vweb_result_type { // ast.void_type {
|
2020-07-25 00:02:44 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
*/
|
2021-11-15 14:47:29 +01:00
|
|
|
g.comptime_for_method = method.name
|
2021-03-01 01:01:56 +01:00
|
|
|
g.writeln('/* method $i */ {')
|
2020-12-03 16:02:48 +01:00
|
|
|
g.writeln('\t${node.val_var}.name = _SLIT("$method.name");')
|
2020-07-25 00:02:44 +02:00
|
|
|
if method.attrs.len == 0 {
|
|
|
|
g.writeln('\t${node.val_var}.attrs = __new_array_with_default(0, 0, sizeof(string), 0);')
|
|
|
|
} else {
|
2020-08-10 02:00:14 +02:00
|
|
|
attrs := cgen_attrs(method.attrs)
|
2021-01-23 09:33:22 +01:00
|
|
|
g.writeln(
|
|
|
|
'\t${node.val_var}.attrs = new_array_from_c_array($attrs.len, $attrs.len, sizeof(string), _MOV((string[$attrs.len]){' +
|
2021-05-24 04:20:45 +02:00
|
|
|
attrs.join(', ') + '}));\n')
|
2020-07-25 00:02:44 +02:00
|
|
|
}
|
2020-09-27 03:32:56 +02:00
|
|
|
if method.params.len < 2 {
|
2020-08-27 15:00:44 +02:00
|
|
|
// 0 or 1 (the receiver) args
|
|
|
|
g.writeln('\t${node.val_var}.args = __new_array_with_default(0, 0, sizeof(MethodArgs), 0);')
|
|
|
|
} else {
|
2020-09-27 03:32:56 +02:00
|
|
|
len := method.params.len - 1
|
2020-08-27 15:00:44 +02:00
|
|
|
g.write('\t${node.val_var}.args = new_array_from_c_array($len, $len, sizeof(MethodArgs), _MOV((MethodArgs[$len]){')
|
|
|
|
// Skip receiver arg
|
2020-09-27 03:32:56 +02:00
|
|
|
for j, arg in method.params[1..] {
|
2020-08-27 15:00:44 +02:00
|
|
|
typ := arg.typ.idx()
|
2021-03-07 14:28:43 +01:00
|
|
|
g.write('{$typ.str(), _SLIT("$arg.name")}')
|
2020-08-27 15:00:44 +02:00
|
|
|
if j < len - 1 {
|
|
|
|
g.write(', ')
|
|
|
|
}
|
2020-09-28 06:13:38 +02:00
|
|
|
g.comptime_var_type_map['${node.val_var}.args[$j].typ'] = typ
|
2020-08-27 15:00:44 +02:00
|
|
|
}
|
2021-05-24 04:20:45 +02:00
|
|
|
g.writeln('}));\n')
|
2020-08-27 15:00:44 +02:00
|
|
|
}
|
|
|
|
mut sig := 'anon_fn_'
|
|
|
|
// skip the first (receiver) arg
|
2020-09-27 03:32:56 +02:00
|
|
|
for j, arg in method.params[1..] {
|
2020-08-27 15:00:44 +02:00
|
|
|
// TODO: ignore mut/pts in sig for now
|
|
|
|
typ := arg.typ.set_nr_muls(0)
|
|
|
|
sig += '$typ'
|
2020-09-27 03:32:56 +02:00
|
|
|
if j < method.params.len - 2 {
|
2020-08-27 15:00:44 +02:00
|
|
|
sig += '_'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sig += '_$method.return_type'
|
|
|
|
styp := g.table.find_type_idx(sig)
|
|
|
|
// println(styp)
|
|
|
|
// if styp == 0 { }
|
|
|
|
// TODO: type aliases
|
|
|
|
ret_typ := method.return_type.idx()
|
2020-09-28 06:13:38 +02:00
|
|
|
g.writeln('\t${node.val_var}.typ = $styp;')
|
|
|
|
g.writeln('\t${node.val_var}.return_type = $ret_typ;')
|
2020-07-25 00:02:44 +02:00
|
|
|
//
|
2020-09-28 06:13:38 +02:00
|
|
|
g.comptime_var_type_map['${node.val_var}.return_type'] = ret_typ
|
|
|
|
g.comptime_var_type_map['${node.val_var}.typ'] = styp
|
2020-07-25 00:02:44 +02:00
|
|
|
g.stmts(node.stmts)
|
|
|
|
i++
|
2021-03-01 01:01:56 +01:00
|
|
|
g.writeln('}')
|
2021-03-16 08:20:45 +01:00
|
|
|
//
|
|
|
|
mut delete_keys := []string{}
|
2020-08-27 15:00:44 +02:00
|
|
|
for key, _ in g.comptime_var_type_map {
|
|
|
|
if key.starts_with(node.val_var) {
|
2021-03-16 08:20:45 +01:00
|
|
|
delete_keys << key
|
2020-08-27 15:00:44 +02:00
|
|
|
}
|
|
|
|
}
|
2021-03-16 08:20:45 +01:00
|
|
|
for key in delete_keys {
|
|
|
|
g.comptime_var_type_map.delete(key)
|
|
|
|
}
|
2020-07-03 15:10:39 +02:00
|
|
|
}
|
2020-07-25 00:02:44 +02:00
|
|
|
} else if node.kind == .fields {
|
|
|
|
// TODO add fields
|
2022-02-11 21:00:13 +01:00
|
|
|
if sym.kind == .struct_ {
|
|
|
|
sym_info := sym.info as ast.Struct
|
|
|
|
if sym_info.fields.len > 0 {
|
2021-01-25 17:08:48 +01:00
|
|
|
g.writeln('\tFieldData $node.val_var = {0};')
|
2020-07-25 00:02:44 +02:00
|
|
|
}
|
2022-02-11 21:00:13 +01:00
|
|
|
g.inside_comptime_for_field = true
|
|
|
|
for field in sym_info.fields {
|
2021-11-15 14:47:29 +01:00
|
|
|
g.comptime_for_field_var = node.val_var
|
|
|
|
g.comptime_for_field_value = field
|
2022-02-11 21:00:13 +01:00
|
|
|
g.comptime_for_field_type = field.typ
|
2021-03-01 01:01:56 +01:00
|
|
|
g.writeln('/* field $i */ {')
|
2020-12-03 16:02:48 +01:00
|
|
|
g.writeln('\t${node.val_var}.name = _SLIT("$field.name");')
|
2020-07-25 00:02:44 +02:00
|
|
|
if field.attrs.len == 0 {
|
|
|
|
g.writeln('\t${node.val_var}.attrs = __new_array_with_default(0, 0, sizeof(string), 0);')
|
|
|
|
} else {
|
2020-08-10 02:00:14 +02:00
|
|
|
attrs := cgen_attrs(field.attrs)
|
2021-01-23 09:33:22 +01:00
|
|
|
g.writeln(
|
|
|
|
'\t${node.val_var}.attrs = new_array_from_c_array($attrs.len, $attrs.len, sizeof(string), _MOV((string[$attrs.len]){' +
|
2021-05-24 04:20:45 +02:00
|
|
|
attrs.join(', ') + '}));\n')
|
2020-07-25 00:02:44 +02:00
|
|
|
}
|
2021-12-19 17:25:18 +01:00
|
|
|
// field_sym := g.table.sym(field.typ)
|
2020-12-03 16:02:48 +01:00
|
|
|
// g.writeln('\t${node.val_var}.typ = _SLIT("$field_sym.name");')
|
2020-08-27 15:00:44 +02:00
|
|
|
styp := field.typ
|
2022-03-24 10:45:06 +01:00
|
|
|
g.writeln('\t${node.val_var}.typ = $styp.idx();')
|
2020-07-25 00:02:44 +02:00
|
|
|
g.writeln('\t${node.val_var}.is_pub = $field.is_pub;')
|
|
|
|
g.writeln('\t${node.val_var}.is_mut = $field.is_mut;')
|
2021-06-16 19:33:30 +02:00
|
|
|
g.writeln('\t${node.val_var}.is_shared = ${field.typ.has_flag(.shared_f)};')
|
2020-09-28 06:13:38 +02:00
|
|
|
g.comptime_var_type_map['${node.val_var}.typ'] = styp
|
2020-07-25 00:02:44 +02:00
|
|
|
g.stmts(node.stmts)
|
|
|
|
i++
|
2021-03-01 01:01:56 +01:00
|
|
|
g.writeln('}')
|
2022-02-11 21:00:13 +01:00
|
|
|
g.comptime_for_field_type = 0
|
2020-07-23 17:19:37 +02:00
|
|
|
}
|
2022-02-11 21:00:13 +01:00
|
|
|
g.inside_comptime_for_field = false
|
2020-07-25 18:58:23 +02:00
|
|
|
g.comptime_var_type_map.delete(node.val_var)
|
2020-07-05 16:44:23 +02:00
|
|
|
}
|
2021-04-25 17:29:26 +02:00
|
|
|
} else if node.kind == .attributes {
|
|
|
|
if sym.info is ast.Struct {
|
|
|
|
if sym.info.attrs.len > 0 {
|
|
|
|
g.writeln('\tStructAttribute $node.val_var = {0};')
|
|
|
|
}
|
|
|
|
for attr in sym.info.attrs {
|
|
|
|
g.writeln('/* attribute $i */ {')
|
|
|
|
g.writeln('\t${node.val_var}.name = _SLIT("$attr.name");')
|
|
|
|
g.writeln('\t${node.val_var}.has_arg = $attr.has_arg;')
|
|
|
|
g.writeln('\t${node.val_var}.arg = _SLIT("$attr.arg");')
|
2021-06-27 18:05:32 +02:00
|
|
|
g.writeln('\t${node.val_var}.kind = AttributeKind__$attr.kind;')
|
2021-07-23 22:24:56 +02:00
|
|
|
g.stmts(node.stmts)
|
2021-04-25 17:29:26 +02:00
|
|
|
g.writeln('}')
|
|
|
|
}
|
|
|
|
}
|
2020-07-03 15:10:39 +02:00
|
|
|
}
|
2021-03-01 01:01:56 +01:00
|
|
|
g.indent--
|
|
|
|
g.writeln('}// \$for')
|
2020-07-03 15:10:39 +02:00
|
|
|
}
|
2021-02-11 01:22:49 +01:00
|
|
|
|
2021-11-15 14:47:29 +01:00
|
|
|
fn (mut g Gen) comptime_if_to_ifdef(name string, is_comptime_optional bool) ?string {
|
2021-02-11 01:22:49 +01:00
|
|
|
match name {
|
|
|
|
// platforms/os-es:
|
|
|
|
'windows' {
|
|
|
|
return '_WIN32'
|
|
|
|
}
|
|
|
|
'ios' {
|
|
|
|
return '__TARGET_IOS__'
|
|
|
|
}
|
|
|
|
'macos' {
|
|
|
|
return '__APPLE__'
|
|
|
|
}
|
|
|
|
'mach' {
|
|
|
|
return '__MACH__'
|
|
|
|
}
|
|
|
|
'darwin' {
|
|
|
|
return '__DARWIN__'
|
|
|
|
}
|
|
|
|
'hpux' {
|
|
|
|
return '__HPUX__'
|
|
|
|
}
|
|
|
|
'gnu' {
|
|
|
|
return '__GNU__'
|
|
|
|
}
|
|
|
|
'qnx' {
|
|
|
|
return '__QNX__'
|
|
|
|
}
|
|
|
|
'linux' {
|
|
|
|
return '__linux__'
|
|
|
|
}
|
2021-07-09 02:26:43 +02:00
|
|
|
'serenity' {
|
|
|
|
return '__serenity__'
|
|
|
|
}
|
2021-07-13 10:09:32 +02:00
|
|
|
'vinix' {
|
|
|
|
return '__vinix__'
|
|
|
|
}
|
2021-02-11 01:22:49 +01:00
|
|
|
'freebsd' {
|
|
|
|
return '__FreeBSD__'
|
|
|
|
}
|
|
|
|
'openbsd' {
|
|
|
|
return '__OpenBSD__'
|
|
|
|
}
|
|
|
|
'netbsd' {
|
|
|
|
return '__NetBSD__'
|
|
|
|
}
|
|
|
|
'bsd' {
|
|
|
|
return '__BSD__'
|
|
|
|
}
|
|
|
|
'dragonfly' {
|
|
|
|
return '__DragonFly__'
|
|
|
|
}
|
|
|
|
'android' {
|
|
|
|
return '__ANDROID__'
|
|
|
|
}
|
|
|
|
'solaris' {
|
|
|
|
return '__sun'
|
|
|
|
}
|
|
|
|
'haiku' {
|
2021-07-20 15:13:23 +02:00
|
|
|
return '__HAIKU__'
|
2021-02-11 01:22:49 +01:00
|
|
|
}
|
|
|
|
//
|
|
|
|
'js' {
|
|
|
|
return '_VJS'
|
|
|
|
}
|
|
|
|
// compilers:
|
|
|
|
'gcc' {
|
|
|
|
return '__V_GCC__'
|
|
|
|
}
|
|
|
|
'tinyc' {
|
|
|
|
return '__TINYC__'
|
|
|
|
}
|
|
|
|
'clang' {
|
|
|
|
return '__clang__'
|
|
|
|
}
|
|
|
|
'mingw' {
|
|
|
|
return '__MINGW32__'
|
|
|
|
}
|
|
|
|
'msvc' {
|
|
|
|
return '_MSC_VER'
|
|
|
|
}
|
|
|
|
'cplusplus' {
|
|
|
|
return '__cplusplus'
|
|
|
|
}
|
|
|
|
// other:
|
2021-05-27 17:36:07 +02:00
|
|
|
'threads' {
|
|
|
|
return '__VTHREADS__'
|
|
|
|
}
|
2021-03-20 14:16:36 +01:00
|
|
|
'gcboehm' {
|
|
|
|
return '_VGCBOEHM'
|
|
|
|
}
|
2021-02-11 01:22:49 +01:00
|
|
|
'debug' {
|
|
|
|
return '_VDEBUG'
|
|
|
|
}
|
2021-03-10 18:26:34 +01:00
|
|
|
'prod' {
|
|
|
|
return '_VPROD'
|
|
|
|
}
|
2022-01-21 02:26:05 +01:00
|
|
|
'profile' {
|
|
|
|
return '_VPROFILE'
|
|
|
|
}
|
2021-02-11 01:22:49 +01:00
|
|
|
'test' {
|
|
|
|
return '_VTEST'
|
|
|
|
}
|
|
|
|
'glibc' {
|
|
|
|
return '__GLIBC__'
|
|
|
|
}
|
|
|
|
'prealloc' {
|
|
|
|
return '_VPREALLOC'
|
|
|
|
}
|
|
|
|
'no_bounds_checking' {
|
|
|
|
return 'CUSTOM_DEFINE_no_bounds_checking'
|
|
|
|
}
|
2021-04-09 22:24:25 +02:00
|
|
|
'freestanding' {
|
|
|
|
return '_VFREESTANDING'
|
|
|
|
}
|
2021-02-11 01:22:49 +01:00
|
|
|
// architectures:
|
|
|
|
'amd64' {
|
|
|
|
return '__V_amd64'
|
|
|
|
}
|
2021-04-26 18:01:42 +02:00
|
|
|
'aarch64', 'arm64' {
|
|
|
|
return '__V_arm64'
|
2021-02-11 01:22:49 +01:00
|
|
|
}
|
2022-04-30 08:32:46 +02:00
|
|
|
'arm32' {
|
|
|
|
return '__V_arm32'
|
|
|
|
}
|
|
|
|
'i386' {
|
|
|
|
return '__V_x86'
|
|
|
|
}
|
2021-02-11 01:22:49 +01:00
|
|
|
// bitness:
|
|
|
|
'x64' {
|
|
|
|
return 'TARGET_IS_64BIT'
|
|
|
|
}
|
|
|
|
'x32' {
|
|
|
|
return 'TARGET_IS_32BIT'
|
|
|
|
}
|
|
|
|
// endianness:
|
|
|
|
'little_endian' {
|
|
|
|
return 'TARGET_ORDER_IS_LITTLE'
|
|
|
|
}
|
|
|
|
'big_endian' {
|
|
|
|
return 'TARGET_ORDER_IS_BIG'
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if is_comptime_optional
|
|
|
|
|| (g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all) {
|
|
|
|
return 'CUSTOM_DEFINE_$name'
|
|
|
|
}
|
|
|
|
return error('bad os ifdef name "$name"') // should never happen, caught in the checker
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return none
|
|
|
|
}
|